Home Blog Page 73

Giới thiệu View Controller và vòng đời view controller trong lập trình IOS

view controller
Giới thiệu View Controller và vòng đời view controller trong lập trình IOS

Bài viết được sự cho phép của tác giả Trần Hữu Cương

I.Giới thiệu

View Controller là một đối tượng trong mô hình MVC (Model View Controller).

View Controller là một liên kết quan trọng giữa giao diện và dữ liệu.

Một trong những vai trò quan trọng của View Controller là quản lý các View hiển thị nội dung.

Các View Controller đều có thể giao tiếp và kết hợp với các View Controller khác.

 View controller cung cấp nhiều hành vi (behaviour) phổ biến cho tất cả các ứng dụng iOS.

Thông thường, những hành vi này được xây dựng vào các lớp cơ sở (base class).

  3 sai lầm các iOS Developers thường mắc phải
  Build một ứng dụng Chat cho Android & iOS bằng Contus Fly như thế nào?

Xem thêm tuyển dụng iOS lương cao trên TopDev

II.Các loại View Controller

View Controller gồm 2 loại là Content View Controller và Container View Controller.

Content view controller thể hiện nội dung trên màn hình bằng cách sử dụng một view hay một nhóm các view được tổ chức thành một hệ thống view.

 Ví dụ: Một dạng của content view controller là table view, được sử dụng để thể hiện dữ liệu dạng bảng (gồm nhiều dòng dữ liệu).

Container view controller là thành phần có khả năng chứa và quản lý nhiều view controller con bên trong.

Ví dụ: Tab bar là một dạng của container view controller. Bên trong Tab bar chứa nhiều tab con, mỗi một tab con là thể hiện của một view controller mà tab bar quản lý.

III.Vòng đời View Controller

Vòng đời của một view controller  là được tính từ lúc nó được nạp vào bộ nhớ(RAM) cho tới khi nó bị huỷ khỏi bộ nhớ.

LoadView

  • Hàm này sẽ được gọi đầu tiên khi khởi tạo một view controller.

viewDidLoad

  • Khi view controller đã được nạp vào bộ nhớ, thì hàm viewDidLoad được gọi.
  • Chỉ được gọi một lần duy nhất trong chu kỳ sống của view đó thôi,giống hàm onCreat() trong Android
  • Thường dùng để chuẩn bị data hoặc là khởi tạo các giá trị mặc định cho các object cũng như UI trên màn hình.

viewDidUnload

  • Khi app của bạn nhận được cảnh báo từ hệ thống về trạng thái bộ nhớ đang gần hết thì hàm này sẽ được gọi
  • Tại hàm này sẽ giải phóng bớt các property không cần dùng, gán nil chúng để giải phóng bộ nhớ.

viewWillAppear

  • Hàm sẽ được gọi trước khi một view được thêm vào hệ thống view và trước animation hiển thị một view.

viewDidAppear

  • Hàm sẽ được gọi khi một view đã được thêm vài hệ thống view và đã hiển thị lên màn hình.

viewWillDisappear

  • Gọi khi một view đã được ẩn khỏi màn hình và amination khi ẩn view đó.

viewDidDisappear

  • Gọi khi một view đã được ẩn khỏi màn hình.

Lưu ý khi load dữ liệu tại các hàm:

Nếu dữ liệu là dạng tĩnh và không thay đổi nhiều, bạn nên load chúng ở phương thức viewDidlLoad.

Nếu dữ liệu là động và thay đổi thường xuyên, bạn nên load tại phương thức viewDidAppear.

Lưu ý là tại 2 phương thức, dữ liệu cần phải load theo dạng bất đồng bộ ở một thread khác để tránh ảnh hưởng đến UI.

Ví dụ:Giờ ta thiết lập 2 màn hình trắng và đỏ.

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {

super.viewDidLoad()

// Do any additional setup after loading the view, typically from a nib.

print(“Man Hinh 1 : View DidLoad”)

}

@IBAction func sangmanhinhDo(_ sender: Any) {

let sb = UIStoryboard(name: “Main”, bundle: nil)

let manHinhXanh = sb.instantiateViewController(withIdentifier: “View2Controller”) as! View2Controller

self.navigationController?.pushViewController(manHinhXanh, animated: true)

}

override func viewWillAppear(_ animated: Bool) {

print(“Man Hinh 1 : viewWillAppear”)

}

override func viewDidAppear(_ animated: Bool) {

print(“Man Hinh 1 : viewDidAppear”)

}

override func viewWillDisappear(_ animated: Bool) {

print(“Man Hinh 1 : viewWillDisappear”)

}

override func viewDidDisappear(_ animated: Bool) {

print(“Man Hinh 1 : viewDidDisappear”)

}

Và đây là kết quả sau khi các bạn chạy và khởi động ứng dụng

sẽ gọi 3 func là viewDidLoad, viewWillAppear, viewDidAppear

Khi các bạn click vào button “Sang mang 2”

Và khi nhấn nút back chúng ta sẽ có kết quả sau.

Bài viết gốc được đăng tải tại codecute.com
Có thể bạn quan tâm:
Xem thêm tuyển dụng IT hấp dẫn trên TopDev

Kinh nghiệm Remote work – Làm việc từ xa

Remote work
Remote work

Bài viết được sự cho phép của tác giả Huy Trần

Nhiều người lầm tưởng rằng CNTT nói chung và lập trình nói riêng là ngành làm việc với máy móc, mình chọn đi theo con đường lập trình cũng vì thích ngồi làm việc với máy móc hơn là phải deal với loài người. Nhưng lầm tưởng là lầm tưởng. Nói theo Kinh tế học Mác Lê thì máy tính chỉ là Tư liệu lao động — Công cụ để con người sử dụng, tạo ra giá trị khi làm việc cùng với nhau.

Như mọi ngành nghề khác, lập trình là công việc đòi hỏi tính tương tác cao giữa con người với con người, và nó chỉ thực sự trở nên hiệu quả khi giao tiếp giữa các thành viên trong team diễn ra trơn tru, hiệu quả.

Xem việc làm IT remote đãi ngộ tốt trên TopDev

Mình đã từng lầm tưởng remote work chỉ đơn giản là ôm cái laptop ngồi ở nhà, và code, và rất hí hửng khi công ty cho phép về nhà làm remote. Và rất chán nản khi số lượng các buổi họp hành tăng lên đáng kể khi công ty chuyển sang remote. Mặc cho bác product manager đã cố gắng, trong phạm vi cho phép, bỏ hết các buổi họp không cần thiết. Trong cái khó ló cái ngu các bạn ạ, nghĩ mình làm dev, chỉ cần biết ngồi code chăm chỉ là được, mình tự tin tắt mic, che camera rồi ngồi làm việc của mình, mặc cho các bạn dev khác thảo luận sôi nổi với product manager. Nghĩ như thế là ngon, cần gì chỉ cần trao đổi qua mail và chat là ok. Càng lúc mình càng cảm thấy xa rời dự án và team, bắt đầu xuất hiện cảm giác đuối. Cuối cùng thì tình trạng này kéo theo nhiều hệ lụy khác, mình cũng đánh mất nhiều cơ hội để đóng góp một cách có ý nghĩa vào dự án đang làm và các dự án mới. Nhìn thấy người khác làm việc hiệu quả hơn mình, đâm ra ganh tị với đồng nghiệp, stress với bản thân, dỗi với sếp, thế là mình burn out, và quit.

May mắn là, sau khi quit thì mình lao vào một giai đoạn phỏng vấn mới, và ở giai đoạn này mình được cơ hội nói chuyện với rất nhiều bạn dev ở nhiều môi trường khác nhau, mình không ngại nói cho họ nghe lý do mình nghỉ việc ở công ty cũ, và các bạn ấy cũng nhiệt tình chia sẻ những kinh nghiệm làm việc trong môi trường remote mà họ đúc kết được, vì họ cũng từng trải qua giai đoạn đi xuống như thế giống mình.

Xem thêm việc làm IOT Engineering hấp dẫn trên TopDev

Một số kinh nghiệm mà mình đúc kết được sau quá trình đó:

  • Phải luôn aware được rằng, giao tiếp là yếu tố then chốt để thành công trong một product team. Đồng thời phải biết giao tiếp qua mạng khó hơn giao tiếp trực tiếp rất nhiều lần.
  • Email và chat không phải là công cụ thay thế hoàn toàn cho việc giao tiếp trong team, đôi lúc 10,000 dòng chat có thể rút gọn bằng 15 phút nói chuyện trực tiếp. Không nên lạm dụng email, chat để tránh né việc phải gọi điện, video call.
  • Luôn tìm cách engage trong các buổi họp online, bằng cách bật camera lên để cả mình và mọi người biết rằng mình đang tập trung cho buổi họp, tắt camera cũng được nếu bạn tự tin là mình có thể engage tốt.
  • Không nhất thiết phải ngồi nói huyên thuyên suốt cả buổi họp, nhưng phải biết rằng, người ta invite mình vô một buổi họp vì muốn mình đóng góp giá trị cho buổi họp đó, nếu join vào chỉ để tắt camera mute mic làm việc riêng thì mình đang việc làm sai cách rồi.
  • Thường chúng ta có xu hướng im lặng, không đặt câu hỏi, không góp ý, ai nói gì cũng gật hoặc đồng tình, khi người nào đó hỏi: “Có ai có câu hỏi gì không?” thì phần lớn chọn cách im lặng. Có một tip khá hay để thoát khỏi tính im lặng bầy đàn này, đó là không ngại hỏi ngu.
  • Sẽ có nhiều lúc trong một buổi họp, ta tự hỏi là liệu mình có nên nói hay hỏi về chuyện này không nhỉ? Sau đó lại thôi, im lặng không nói gì vì sợ mọi người biết rồi hoặc sợ bị nói là ngu. Thường những khi tự đặt ra câu hỏi như vậy, thì 99% là nên hỏi.
  • Có đôi lúc vì thiếu tập trung nên mình không biết cuộc họp đang nói về vấn đề gì, dẫn đến không biết gì để mà phát biểu góp ý, những lúc thế này chúng ta có thể chữa cháy bằng cách nhẹ nhàng hỏi lại vấn đề đang được bàn luận, và hỏi tiếp những câu hỏi follow up để gợi mở được hướng thảo luận. (vẫn là về chuyện willing to look stupid).

Những kinh nghiệm này là một phần những gì mình rút ra được từ đợt burnt out vừa qua, nay tiện tay ghi ra không lại quên hết. Tất nhiên là từ trải nghiệm của bản thân mình, YMMV. Còn bạn thì sao? Thời gian làm việc remote vừa qua các bạn cảm thấy thế nào? Nếu không ngại thì hãy comment để chia sẻ ở bên dưới nhé. 😀

Bài viết gốc được đăng tải tại thefullsnack.com

Có thể bạn quan tâm:

Xem thêm tuyển dụng CNTT hấp dẫn trên TopDev

TOP 15 Công Ty IT Nhật Bản Tại Việt Nam

top công ty it nhật bản tại việt nam
TOP 15 Công Ty IT Nhật Bản Tại Việt Nam

Tại Việt Nam hiện nay đã ghi nhận sự góp mặt của rất nhiều các công ty đến từ Nhật Bản,  nhất là trong lĩnh vực công nghệ thông tin. Bài viết dưới đây sẽ cung cấp cho người đọc thông tin về top công ty IT Nhật Bản tại Việt Nam đang phát triển mạnh mẽ. Đây chính là cơ sở để người đọc có thể tham khảo và sử dụng cho công việc hoặc tuyển dụng của mình.

top công ty it nhật bản tại việt nam
TOP Công Ty IT Nhật Bản Tại Việt Nam

*Số thứ tự trong bài viết chỉ nhằm liệt kê các công ty, không nhằm mục đích xếp hạng hay đánh giá

1. Hybrid Technologies – công ty đã và đang phát triển hàng nghìn dự án liên quan đến công nghệ hybrid, lập trình blockchain hay trí tuệ nhân tạo.

2. SoftBank Telecom Việt Nam – chuyên bán, tư vấn các dịch vụ liên quan đến CNTT và mạng như điện toán đám mây, Internet, thiết bị mạng máy chủ…

3. KDDI Việt Nam – là một thành viên của tập đoàn KDDI chuyên cung cấp cơ sở hạ tầng CNTT và xây dựng hệ thống.

4. Koei Tecmo Việt Nam – chuyên về phát triển game như thiết kế Games 3D, chế tác đồ họa, lập trình và kiểm thử…

5. NTT Communication Việt Nam – chuyên phát triển phần mềm, tích hợp hệ thống và mạng lưới…

6. DTS Software Việt Nam – hoạt động trong hai lĩnh vực chính là dịch vụ phát triển và bảo trì hệ thống IT, phần mềm và Business Process Outsourcing.

7. Framgia Việt Nam – phát triển phần mềm cũng như sản xuất các sản phẩm công nghệ trực tuyến. Ngoài ra, công ty cũng nghiên cứu và phát triển các sản phẩm công nghệ mới sử dụng công nghệ AI, Blockchain, VR & AR.

8. Hanatour Japan System Vietnam – chuyên phát triển các hệ thống web ứng dụng và app di động phục vụ cho các công ty thuộc lĩnh vực du lịch và dịch vụ liên quan.

9. System EXE Việt Nam – chuyên tư vấn thiết kế và sản xuất phần mềm quy mô lớn cho các đối tác hàng đầu tại Nhật Bản.

10. Fujinet Việt Nam – công ty chuyên phát triển các phần mềm nghiệp vụ, phần mềm đóng gói, phần mềm điều khiển, phần mềm nhúng,…

11. Evolable Asia – cung cấp dịch vụ phát triển Offshore và LPO/Coding với hình thức “các phòng Lab” hoàn toàn khác biệt so với các dịch vụ IT truyền thống.

12. Orient Software Development Corp

Phần mềm Phương Đông là một công ty phát triển phần mềm chuyên nghiệp và là đối tác có giá trị của bạn trong việc sản xuất nhanh chóng các giải pháp phần mềm.

Chúng tôi có ba nguyên lý cơ bản – Đổi mới, Minh bạch và Nhanh nhẹn – trọng tâm của các tương tác giữa nhân viên và khách hàng của chúng tôi

13. Techbase VietNam – chuyên phát triển các lĩnh vực về thương mại điện tử cũng như các dịch vụ truyền thông.

14. 1PAC Việt Nam – cung cấp các dịch vụ về lên kế hoạch, tư vấn và xây dựng các hệ thống và phần mềm theo yêu cầu của khách hàng.

15. SPLUS-SOFTWARE – là một outsourcing company chuyên cung cấp các dịch vụ hỗ trợ và bảo trì phần mềm, kiểm thử phần mềm,…

Hiện tại công ty đang có tuyển dụng các vị trí như:

  • FRONT-END DEVELOPER (REACTJS)
  • RUBY ON RAILS DEVELOPER

Bạn có thể tham khảo chi tiết tại đây

(Tiếp tục update)

Hi vọng các thông tin trên đây đã cung cấp cho người đọc thêm một số cái tên công ty chuyên về IT giúp bạn thuận tiện hơn trong công việc. Đón đọc thêm nhiều bài viết bổ ích khác tại topdev.vn/blog với các thông tin được cập nhật liên tục.


Tuyển Dụng Nhân Tài IT Cùng TopDev
Đăng ký nhận ưu đãi & tư vấn về các giải pháp Tuyển dụng IT & Xây dựng Thương hiệu tuyển dụng ngay!
Hotline: 028.6273.3496 – Email: contact@topdev.vn
Dịch vụ: https://topdev.vn/page/products

Gần 1 tỷ đồng giải thưởng cho bạn trẻ yêu công nghệ tại FPT Techday 2021

‘Đấu trường công nghệ’ trong khuôn khổ FPT Techday 2021 có tổng giá trị giải thưởng đến 1 tỷ đồng, dành cho học sinh THCS, THPT, sinh viên và bạn trẻ yêu công nghệ.

Sự kiện công nghệ lớn nhất năm FPT Techday 2021 của FPT sẽ diễn ra dưới hình thức trực tuyến vào ngày 2 và 3/12 với nhiều hoạt động xoay quanh chủ đề “Tái thiết toàn diện, bứt phá trong bình thường xanh” (Thrive in The Green Normal). Trong đó, sân chơi ‘Đấu trường công nghệ’ hằng năm là một trong ba yếu tố thu hút sự quan tâm của hàng nghìn bạn trẻ đam mê công nghệ, bên cạnh cơ hội trải nghiệm triển lãm và các phiên hội thảo chia sẻ về xu hướng công nghệ chuyên sâu.

Đấu trường công nghệ trong khuôn khổ FPT Techday 2021 có tổng giá trị giải thưởng đến 1 tỷ đồng. Ảnh: FPT Techday 2021

‘Đấu trường công nghệ’ trong khuôn khổ FPT Techday 2021 có tổng giá trị giải thưởng đến 1 tỷ đồng. Ảnh: FPT Techday 2021

‘Đấu trường công nghệ’

‘Đấu trường công nghệ’ được tổ chức với hai nội dung thi đấu: Avengers Lockdown và Đấu sĩ Coder, dành cho các bạn trẻ từ 12 đến 25 tuổi, biết sử dụng một trong những ngôn ngữ lập trình sau: C#, C++, Java, Js, Go, Python. Tại đây, thí sinh vừa có cơ hội cọ xát, khẳng định năng lực công nghệ của bản thân vừa có thể nhận các giải thưởng với tổng giá trị lên đến 1 tỷ đồng.

Trong đó, Avengers Lockdown sẽ mô phỏng trận chiến với Covid-19. Các đội thi sẽ lập trình các bot hóa thân thành “siêu anh hùng” có nhiệm vụ tham gia truy vết các ca lây nhiễm để khoanh vùng dịch, đưa đi điều trị, truy tìm người tiếp xúc để cách ly tập trung. Kết quả chung cuộc phụ thuộc vào số lượng người dân được cứu và vật phẩm tìm thấy. Mỗi đội chơi không quá 4 người, thi đối kháng với đối thủ để tìm ra đội thắng cuộc.

Đội chiến thắng sẽ nhận được 20 triệu đồng tiền mặt cùng một năm sử dụng tài nguyên AI, Cloud của FPT, trị giá 500 triệu đồng. Giải nhì và ba có phần thưởng lần lượt là 10 và 5 triệu đồng.

Nội dung Đấu sĩ Coder gồm ba bảng thi cho ba đối tượng học sinh THCS, THPT và sinh viên để tìm ra người có khả năng code nhanh và chính xác nhất đề bài từ ban tổ chức. Thí sinh tham gia các trận đấu sẽ code trên nền tảng CodeLearn để giải quyết một số bài toán do ban tổ chức đưa ra. 150 thí sinh có điểm số cao nhất vòng loại ở mỗi bảng đấu (bảng THCS, THPT và sinh viên) sẽ được sắp xếp vào một trong hai trận chung kết.

Giải thưởng ở phần này có giá trị đến 10 triệu đồng mỗi thí sinh (tùy theo từng bảng), cùng hai điện thoại iPhone 13 và hàng trăm phần quà hấp dẫn khác.

*Độc giả đăng ký tham gia tại đây.

Trải nghiệm triển lãm công nghệ “Thành phố xanh thông minh”

Cộng đồng yêu công nghệ sẽ có cơ hội tiếp cận và trải nghiệm đầy đủ về một mô hình thành phố thông minh và an toàn trong dịch bệnh, bối cảnh mới bình thường xanh – “sống chung với đại dịch” tại hạng mục triển lãm công nghệ trên nền tảng trực tuyến.

Với chủ đề Thành phố xanh thông minh (Green Smart City), người xem có thể chứng kiến các hoạt động của chính quyền, tổ chức, doanh nghiệp và đời sống của cá nhân vận hành theo phương thức mới.

Trong đó, mô hình thành phố này xoay chuyển dựa trên nền tảng cốt lõi là công nghệ, thông qua các giải pháp, sản phẩm công nghệ. Từ đó, tái thiết lại hoạt động của lĩnh vực, tổ chức cá nhân – nơi mọi thứ sẽ được kết nối thông minh, chủ động quản trị, linh hoạt ứng phó và đảm bảo an toàn trong mọi tình huống.

Thành phố Xanh Thông Minh (Green Smart City).

Thành phố Xanh Thông Minh (Green Smart City). Ảnh: FPT Techday 2021

Phiên hội thảo chuyên sâu về xu thế công nghệ

Hội thảo quy tụ hơn 50 diễn giả là lãnh đạo các doanh nghiệp, chuyên gia tư vấn, chuyên gia công nghệ hàng đầu trong và ngoài nước như ông Trương Gia Bình – Chủ tịch Hội đồng quản trị FPT; ông Nguyễn Văn Khoa – Tổng giám đốc Tập đoàn FPT; ông Nguyễn Thành Trung – Giám đốc điều hành Sky Mavis; ông Lê Hồng Việt – Tổng giám đốc FPT Smart Cloud; bà Trần Thị Thanh Vân – Phó tổng giám đốc phụ trách Chuyển đổi số và Marketing của Goldsun Media Group; ông Yuichi Ui – chuyên gia Chiến lược Giải pháp và Kiến trúc đa đám mây của VMware…

Trong đó, ở phiên chuyên đề chính, ông Trương Gia Bình sẽ trình bày Sứ mệnh của công nghệ trong bình thường xanh – Công nghệ vị nhân sinh. Nội dung chính gồm: công nghệ cứu sinh mạng (chatbot AI hỗ trợ truy vết, tư vấn, thu thập thông tin các ca bệnh); công nghệ cứu doanh mạnh (FPT eCovax); công nghệ giúp bứt phá kinh tế (Việt Nam và trên toàn cầu) và công nghệ chỉ huy chống dịch.

Ngoài ra, các phiên hội thảo tập trung bàn sâu về các xu thế công nghệ và đưa ra các định hướng phát triển công nghệ tương lai như Blockchain, AI, Cloud… trong nhiều lĩnh vực như bất động sản, tài chính, ngân hàng hay sản xuất.vvvvvv

Bài viết gốc được đăng tải tại vnexpress.net

Sự kiện trực tuyến: “Tech Talk: The Evolution of Scalable Mobile Application Development at Home Credit Vietnam”

Tech Talk: The Evolution of Scalable Mobile Application Development at Home Credit Vietnam

Hơn 12 năm vận hành và phát triển tại Việt Nam, Home Credit không ngừng ứng dụng công nghệ nhằm giúp khách hàng “Dự định trong tầm tay – Sống vui thêm mỗi ngày”. Và tối ưu hóa trải nghiệm của người dùng trên ứng dụng di động là một phần quan trọng trong việc hiện thực hóa mục tiêu thay đổi cách thế giới mua sắm.

Tech Talk: The Evolution of Scalable Mobile Application Development at Home Credit Vietnam

Tham gia ngay sự kiện “Tech Talk: The Evolution of Scalable Mobile Application Development at Home Credit Vietnam” để tìm hiểu về cách vận hành team và cách triển khai các công nghệ mới mà các chuyên gia công nghệ tại Home Credit đã và đang sử dụng trong việc phát triển ứng dụng di động cho hàng triệu người dùng.

  • Thời gian: 02/12/2021 | 18:30 – 20:00
  • Hình thức: Sự kiện trực tuyến qua Zoom
  • Ngôn ngữ: Tiếng Việt và tiếng Anh
  • Đăng ký: bit.ly/HomeCreditTechTalk

Nhận được gì khi tham gia sự kiện?

Tham gia sự kiện The Evolution of Scalable Mobile Application Development at Home Credit Vietnam”, bạn sẽ có cơ hội:

  • Tìm hiểu về sự phát triển ứng dụng di động tại Home Credit Việt Nam đã thay đổi ra sao.
  • Khám phá cách áp dụng Flutter vào ứng dụng di động để đồng bộ trải nghiệm người dùng, chia sẻ nguồn lực nhằm tối ưu quá trình phát triển của các chức năng cốt lõi được sử dụng bởi hàng triệu người dùng và hàng ngàn nhân sự tại nhiều quốc gia.
  • Giao lưu và đặt câu hỏi trực tiếp với các chuyên gia đầu ngành để hiểu rõ hơn về các công nghệ, cách thức triển khai và vận hành chúng.
  • Tham dự mini game và nhận những phần quà hấp dẫn.

Diễn giả trong sự kiện

🌟 Anh PETER ZAJIC, Chief Information Officer – Home Credit Việt Nam

Anh Peter Zajic là người đảm nhiệm tất cả những công việc liên quan đến ứng dụng doanh nghiệp, cơ sở hạ tầng & hệ thống tại Home Credit Việt Nam. Với chuyên môn sâu, khả năng lãnh đạo và truyền cảm hứng mạnh mẽ cho đội nhóm, anh đã có hơn 15 năm liên tục thành công trong việc lãnh đạo các đội nhóm IT của công ty. Hiện tại anh hiện đảm nhiệm chức vụ CIO tại Home Credit Việt Nam.

🌟 Anh LÊ HOÀNG HẢI, Head Of IT Development – Home Credit Việt Nam

Sở hữu hơn 12 năm kinh nghiệm thực chiến từ các dự án quy mô lớn trong nhiều loại công nghệ & lĩnh vực kinh doanh khác nhau, anh hiện là người đóng vai trò quan trọng trong việc xác định các chiến lược Công nghệ và giám sát thực hiện quy trình đầu – cuối (End-to-end) tại Home Credit.

🌟 Anh LÊ HOÀNG VIỆT, IT Information Security Manager – Home Credit Việt Nam

Với nhiều thành tích ấn tượng trong 9 năm hoạt động tại lĩnh vực Công nghệ Đám mây và An toàn Thông tin, anh đóng góp những giá trị to lớn trong việc đảm bảo an toàn cho các nguồn thông tin và điện toán của Home Credit.

🌟 Anh LƯƠNG ĐỖ MINH HƯNG, Senior Mobile Developer – Home Credit Việt Nam

Anh đã có 7 năm kinh nghiệm vững chắc về chuyên môn, kiến ​​thức chuyên sâu về Android & Flutter trong công việc Phát triển ứng dụng di động. Anh đã từng xây dựng thành công các tính năng cốt yếu cho ứng dụng Sendo, đồng thời đóng vai trò quan trọng trong công việc phát triển ứng dụng di động tại Home Credit.

Agenda sự kiện

Có thể là hình ảnh về văn bản cho biết 'HOME CREDIT Giảipháp chính lùng TO PDev Tech Talk The EVOLUTION of Scalable Mobile Application Development at Home Credit Vietnam AGENDA 18:30 18:35 DECEMBER UU 6:30 8:00 PM 02 Live on Zoom Đón khách 18:35- 18:40 tham Khaimacsựkiện Peter Zajic CIO 18:40 19:40 Topic: "The Evolution of Scalable Mobile Application Development Home Credit Vietnam" Anh Lương Đỗ Minh Hưng SeniorMobile Developer 19:40 20:00 Hỏi đáp (Q&A) với dàn diễn ĐĂNG KÝ NGAY Sốngvui HOME cùng CREDIT'

  • 18:30 – 18:35 | Đón khách và tham gia mini-game
  • 18:35 – 18:40 | Khai mạc sự kiện | Ông Peter Zajic – CIO
  • 18:40 – 19:40 | Topic: “The Evolution of Scalable Mobile Application Development at Home Credit Vietnam” | Anh Lương Đỗ Minh Hưng – Senior Mobile Developer
  •  19:40 – 20:00 |  Hỏi đáp (Q&A) với dàn diễn giả

ĐĂNG KÝ NGAY 👉 bit.ly/HomeCreditTechTalk

*Nhằm đảm bảo chất lượng sự kiện, BTC sẽ đóng cổng đăng ký khi số lượng đăng ký đạt giới hạn. BTC sẽ gửi mail xác nhận  kèm link tham dự sự kiện khi bạn đăng ký thành công.

12 nguyên tắc trong Agile

nguyên tắc trong agile
12 nguyên tắc trong Agile

Bài viết được sự cho phép của vntesters.com

“12 nguyên tắc trong Agile” và “tuyên ngôn của Agile” là những phần cốt lõi trong Agile. “Tuyên ngôn của Agile” có thể chung chung và “cao cấp” nhưng 12 nguyên tắc trong Agile sẽ mang tính thực tiễn nhiều hơn.

Agile_Elephant

Thỏa mãn yêu cầu của khách hàng thông qua việc giao hàng sớm và liên tục

Giao phần mềm chạy được cho khách hàng một cách thường xuyên (giao hàng tuần hơn là hàng tháng)

2 nguyên tắc trên mình gom lại với nhau vì cơ bản nó chia sẻ ý tưởng giống nhau là giao hàng sớm, liên tục và chạy được cho khách hàng. Dĩ nhiên mục đích của dự án phát triển phần mềm là phát-triển-phần-mềm và làm khách hàng hài lòng và không có gì làm khách hàng hài lòng hơn việc cho khách hàng thấy được sản phẩm của mình thường xuyên và chạy được. Trong Agile, sản phẩm sẽ được demo cho khách hàng thường xuyên (thường là hàng tuần) để cho khách hàng thấy được sản phẩm của mình như thế nào. Nếu có chỗ nào không ổn hay cần cải tiến thì sẽ phản hồi với đội dự án ngay lập tức. Do đó sẽ giúp tránh được tình huống dở khóc dở cười sau khi hoàn thành sản phẩm như “tôi tưởng anh muốn ABC”, “tôi nghĩ mặc định anh sẽ làm XYZ”, v.v

  Agile là gì? Scrum là gì? Các công cụ quản lý dự án theo Agile mà bạn nên biết
  Digital Messaging - Giải Pháp Quản Lý Toàn Diện Dữ Liệu Người Dùng

Xem thêm việc làm Agile lương cao trên TopDev

Chào đón việc thay đổi yêu cầu, thậm chí là những thay đổi yêu cầu muộn

Dù bạn thích hay không thì việc thay đổi yêu cầu từ khách hàng là dường như không thể tránh khỏi và nhiệm vụ của bạn là phải thích ứng với sự thay đổi đó. Thích ứng không có nghĩa là khách hàng yêu cầu gì mình làm cái đó. Khi khách hàng thay đổi yêu cầu, chắc chắn phải có lý do của họ và nhiệm vụ của đội dự án là phải hiểu được lí do đó để có thể điều chỉnh sự thay đổi, tư vấn hay đề nghị giải pháp cho khách hàng tương ứng

Nhà kinh doanh và kỹ sư lập trình phải làm việc cùng nhau hàng ngày trong suốt dự án

“Nhà kinh doanh” ở đây được hiểu nôm na là khách hàng của dự án, những người tài trợ cho dự án. Đội phát triển phải làm việc thường xuyên và gần gũi với khách hàng để hiểu được nhu cầu của họ cũng như cho phép khách hàng hiểu về công việc của đội phát triển. Đó là một trong những lí do mà Agile dường như khó triển khai trong các dự án offshore trong đó rào cản về địa lý, thời gian, ngôn ngữ là một trở ngại lớn.

Các dự án được xây dựng xung quanh những cá nhân có động lực. Cung cấp cho họ môi trường và sự hỗ trợ cần thiết, và tin tưởng họ để hoàn thành công việc 

Như đã chia sẻ, Agile đặt trọng tâm là con người. Con người ở đây chỉ những cá nhân có động lực làm việc với tinh thần cộng tác, chia sẻ và giúp đỡ lẫn nhau. Song song đó, đội dự án sẽ được hỗ trợ những công cụ, môi trường, sự tin tưởng và những đãi ngộ cần thiết để hoàn thành công việc.

Trao đổi trực tiếp mặt đối mặt là phương pháp hiệu quả nhất để truyền đạt thông tin

Sự giao tiếp trao đổi giữa những cá nhân là rất quan trọng và để giao tiếp hiệu quả thì không gì có thể hơn được trực tiếp trao đổi mặt-đối-mặt hay dùng những biểu tượng hình ảnh để chuyển tải thông tin. Bạn sẽ dễ bắt gặp một không khí nhộn nhịp hay những hình ảnh minh họa, biểu tượng, hình vẽ đầy màu sắc trong các dự án Agile vì những điều đó giúp trao đổi thông tin hiệu quả hơn.

Phần mềm chạy được là thước đo chính của tiến độ

Thông tin về tiến độ của dự án rất quan trọng, đặc biệt là đối với Ban quản lý hay các nhà đầu tư cho dự án vì những thông tin đó sẽ giúp họ có thể đưa ra những quyết định. Tuy nhiên, suy cho cùng điều mà họ quan tâm thực ra là sản phẩm đang phát triển có hoạt động tốt hay không. Bạn có thể báo tiến độ là “Đúng kế hoạch” nhưng khi được hỏi sản phẩm chạy được chưa thì câu trả lời là “sắp chạy được” hay “chưa chạy được” sẽ làm khách hàng hoang mang. Do đó, trong Agile bạn phải chuẩn bị tinh thần để “show hàng” cho khách hàng xem.

Phát triển bền vững và duy trì được nhịp độ phát triển liên tục

Trong Agile ưu tiên phát triển bền vững và duy trì nhịp độ phát triển liên tục. Đôi khi dự án cần phải làm thêm giờ nhưng chắc chắc bạn không thể làm 10-12 tiếng/ngày trong nhiều tháng liên tục. Theo mình thấy thì thời gian thực sự cho công việc để mang lại hiệu quả cao nhất là khoảng 4-5 tiếng. Nhiều bạn khi làm thêm giờ thì tự nhủ hay “được hứa” rằng đây chỉ là tạm thời nhưng có khi nhìn lại thì sự tạm thời đó đã được vài tháng rồi. Khi bạn cảm thấy mệt mỏi với cường độ làm việc liên tục và thường xuyên thì đó là dấu hiệu cho thấy dự án Agile của bạn đang có vấn đề.

Liên tục quan tâm đến kĩ thuật và thiết kế để cải tiến sự linh hoạt

Liên tục cải tiến các quy trình, phương pháp, công cụ để tăng mức độ linh hoạt trong dự án. Luôn nghĩ đến những phương pháp mới để code tốt hơn, kiểm thử tốt hơn như  TDD (Test-driven development) , ATDD (Acceptance Test-driven development), kiểm thử tự độngCI v.v

Sự đơn giản là cần thiết – nghệ thuật tối đa hóa lượng công việc chưa hoàn thành

Agile có nghĩa là linh hoạt và để linh hoạt uyển chuyển thì bạn phải tối giản hóa các công việc mình làm. Những việc nào cần thiết và mang lại giá trị thì mọi người sẽ cùng làm. Tuy nhiên việc xác định việc nào mang lại giá trị nhiều khi không đơn giản. Do đó, để đơn giản thì việc có giá trị là việc mà cả nhóm thống nhất và sẽ cam kết thực hiện. Chẳng hạn cả nhóm có thể thống nhất không phải viết “Báo cáo tiến độ hàng ngày” nếu như mọi người đều biết tiến độ của nhau và sếp của bạn cũng không có nhu cầu đọc. Tương tự, bạn cũng không nhất thiết phải mô tả một con bug dài lê thê chỉ để theo đúng định dạng của hệ thống bug trong khi bạn đã báo và trao đổi với Dev về con bug đó và họ đã sửa nó. Tuy nhiên hãy cẩn thận. Không phải bạn bỏ đi là bạn linh hoạt và tối ưu hóa công việc. Vấn đề là bạn bỏ đi những thứ không mang lại giá trị.

Nhóm tự tổ chức

Đây là nguyên tắc cốt lõi trong Agile đồng thời cũng là nguyên tắc gây đau đầu nhất. Ý tưởng là nhóm và cách thành viên sẽ tự quyết định việc mình làm, tự cam kết và tự chịu trách nhiệm cho chất lượng công việc mình làm. Mục đích là để tăng tính chủ động trong công việc. Dĩ nhiên “tự tổ chức” không phải là bạn tập hợp các thành viên và tuyên bố “nào, nhóm tự tổ chức nhé”. Do đó, ban đầu nhóm cũng phải được hướng dẫn, đào tạo để có thể “tự tổ chức”. Quá trình đó có thể gian nan và việc nhóm bạn “tự tổ chức” đến đâu còn tùy thuộc vào nhiều yếu tố như năng lực, nhận thức của thành viên, khả năng hướng dẫn của người hướng dẫn Agile, sự tin tưởng và tôn trọng của ban lãnh đạo, v.v

Thích ứng thường xuyên với sự thay đổi

Nhóm thường xuyên nhìn nhận đánh giá về tình hình dự án sản phẩm để có thể điều chỉnh và thích ứng. Ý tưởng là nhìn lại để tiến lên. Đó là những buổi họp tập trung vào những cái hay cái dở trong những việc mình đang làm để rút tỉa kinh nghiệm và học hỏi lẫn nhau. Những buổi họp dạng vậy thường là những câu hỏi và tự trả lời. Chẳng hạn như:

“Việc gì chúng ta làm chưa tốt” – Trả lời: “Nhóm không tự tổ chức và làm việc có sức ỳ”

“Chúng ta đã làm tốt những việc gì” – Trả lời: “Nhóm sau đó tự tổ chức và làm việc sung hơn”

“Chúng ta đã học được bài học gì” – Trả lời: “Tăng lương giúp giải quyết nhiều vấn đề”

Mình vừa chia sẻ xong 12 nguyên tắc trong Agile. Tới đây thì các bạn cơ bản đã có thể hình dung về Agile về những giá trị cốt lõi trong Agile cũng như những nguyên tắc để trở nên linh hoạt. Nhưng vấn đề là làm thế nào để có thể trở lên linh hoạt? Trong phần tới mình sẽ giới thiệu các bạn “tuyệt chiêu” trong Agile – SCRUM.

Rất vui nếu nhận ý kiến đóng góp, phê bình, chia sẻ từ các bạn.

Bài viết gốc được đăng tải tại vntesters.com

Có thể bạn quan tâm:

Xem thêm tuyển dụng CNTT hấp dẫn trên TopDev

Giới thiệu Feign – Tạo ứng dụng Java RESTful Client không thể đơn giản hơn

giới thiệu feign
Giới thiệu Feign – Tạo ứng dụng Java RESTful Client không thể đơn giản hơn

Bài viết được sự cho phép của tác giả Giang Phan

Trong các bài viết trước chúng ta sử dụng thư viện Jersey clientOkHttpRetrofit để gọi các RESTful API. Trong bài này, tôi sẽ giới thiệu với các bạn thư viện khác là Feign. Thư viện này giúp chúng ta dễ dàng hơn nữa trong phát triển ứng dụng Rest Client.

Giới thiệu Feign

Feign là một HTTP client cho Java, được phát triển bởi Netflix. Mục tiêu của Fiegn là giúp đơn giản hóa HTTP API Client.

Tương tự với các thư viện khác, Feign giúp bạn dễ dàng xử lý dữ liệu JSON hoặc XML sau đó phân tích cú pháp thành Plain Old Java Objects (POJOs). Tất cả các yêu cầu GETPOSTPUT, và DELETE đều có thể được thực thi.

Feign được xây dựng dựa trên một số thư viện mạnh mẽ và công cụ khác để xử lý các request/ response trên mạng bao gồm OkHttp, JAX-RS, Gson, Jackson, JAXB, Ribbon, Hystrix, SOAP, … Các bạn xem thêm các thư viện khác: https://mvnrepository.com/artifact/io.github.openfeign

Feign hỗ trợ một số tính năng mạnh mẽ khác như: Error Handling, Retry, hỗ rợ default method, static method với interface trong java 8.

  10 lý do cho thấy tại sao bạn nên theo học ngôn ngữ lập trình Java
  API là gì? Các nguyên tắc xây dựng Rest API

Xem thêm tuyển dụng Java lương cao trên TopDev

Sử dụng Feign

Ý tưởng của Feign tương tự như Retrofit là sử dụng interface và các annotation để định nghĩa các phương thức request đến API. Với Retrofit, chúng ta còn gặp một chút phiền phức khi phải gọi xử lý Call<Respone>. Sử dụng Feign chúng ta sẽ không thấy sự khác biệt giữa call các method trong interface thông thường và call thông qua Feign.

Để sử dụng Feign chúng ta thực hiện các bước sau:

  • Một class object tương ứng với JSON/ XML data.
  • Một interface dùng để định nghĩa các các phương thức request đến API.
  • Sử dụng Annotations để mô tả yêu cầu HTTP.
  • Tạo một Feign.builder() để khởi tạo các phương thức trong interface đã được định nghĩa.

Các Annotations để mô tả yêu cầu HTTP

Request method

Mỗi phương thức phải có Annotation HTTP cung cấp request method và URL. Feign sử dụng @RequestLine để mô tả các thông tin này.

@RequestLine("GET /api/v1/users?sort=desc")
List getUsers();

Header manipulation

Chúng ta có thể set thông tin static header bằng cách sử dụng annotation @Header ở mức method.

@Headers({
"Cache-Control: max-age=640000",
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@RequestLine("GET /api/v1/users?sort=desc")
List getUsers();

@RequestLine("DELETE /api/v1/users/{id}")
@Headers("Authentication: Bearer {token}")
void deleteUser(@Param("id") int id, @Param("token") String token);

Đối với các kết hợp tham số truy vấn phức tạp, có thể sử dụng @HeaderMap.

@RequestLine("GET /api/v1/users?sort=desc")
List getUsers(@HeaderMap Map<String, String> headers);

Url manipulation

URL request có thể được cập nhật tự động bằng cách sử dụng các khối thay thế và tham số trên phương thức.

Chúng ta có thể sử dụng URL 1 cách động dựa vào biến truyền vào, bằng cách sử dụng anotation @Path.

@RequestLine("GET /api/v1/users/{id}")
User getUser(@Path("id") int userId);

Đối với các kết hợp tham số truy vấn phức tạp, có thể sử dụng @QueryMap.

@RequestLine("GET /api/v1/users?page=1&limit=10&sortBy=createdAt&order=desc")
List getUsers(@QueryMap Map<String, String> options);

Request body

Một đối tượng có thể được chỉ định để sử dụng làm phần thân yêu cầu HTTP với Annotation @Body.

@RequestLine("POST /api/v1/users")
@Headers("Content-Type: application/json")
@Body("%7B\"username\": \"{gpcoder}\", \"password\": \"{gpcoder}\"%7D")
Call createUser(@Body User user);

Form encoded and Multipart

Để gửi dữ liệu form: application/x-www-form-urlencoded và multipart/form-data chúng ta cần sử dụng thêm thư viện feign-form.

Chúng ta cần cung cấp Content-Type trong @Headers và field name trong @Field.

@RequestLine("POST /api/v1/auth")
@Headers("Content-Type: application/x-www-form-urlencoded")
Call getToken(@Field("username") String username, @Field("password") String password);

Các yêu cầu multipart được sử dụng khi @Multipart xuất hiện trên phương thức. Các phần được khai báo bằng cách sử dụng @Part. @Multipart thường được sử dụng để truyền tải file.

@Multipart
@POST("/api/v1/files/upload")
Call uploadFile(@Part("uploadFile") RequestBody uploadFile, @Part("description") RequestBody description);

@RequestLine("POST /send_photo")
Headers("Content-Type: multipart/form-data")
void sendPhoto (@Param("isPublic") Boolean isPublic, @Param("photo") FormData photo);

Ví dụ CRUD Restful Client với Feign

Tạo project

Tạo maven project và khai báo dependency sau trong file pom.xml.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gpcoder</groupId>
    <artifactId>RestfulClientWithFeignExample</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>RestfulClientWithFeignExample</name>
    <url>http://maven.apache.org</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <lombok.version>1.16.20</lombok.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
            <version>10.2.3</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-gson</artifactId>
            <version>10.2.3</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-slf4j</artifactId>
            <version>10.2.3</version>
        </dependency>
        <!-- Support for encoding application/x-www-form-urlencoded and multipart/form-data form -->
        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form</artifactId>
            <version>3.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

Trong project này, tôi sử dụng thư viện gson để convert request/ response data giữa client và server.

Tạo CRUD Restful Client với Feign

Trong ví dụ này, chúng ta sẽ gọi lại các Restful API chúng ta đã tạo ở bài viết trước “JWT – Token-based Authentication trong Jersey 2.x“.

Đầu tiên, chúng ta cần gọi API /auth để lấy token và sau đó chúng ta sẽ attach token này vào mỗi request để truy cập resource.

AuthService.java

package com.gpcoder.service;

import feign.Headers;
import feign.Param;
import feign.RequestLine;

public interface AuthService {

@RequestLine("POST /auth")
@Headers({
"Accept: application/json; charset=utf-8",
"Content-Type: application/x-www-form-urlencoded" })
String getToken(@Param("username") String username, @Param("password") String password);
}

OrderService.java

package com.gpcoder.service;

import java.util.ArrayList;
import java.util.List;

import com.gpcoder.model.Order;

import feign.Headers;
import feign.Param;
import feign.RequestLine;

@Headers({
"Accept: application/json; charset=utf-8",
"Content-Type: application/json" })
public interface OrderService {

@RequestLine("GET /orders/{id}")
String getOrder(@Param("id") int id);

@RequestLine("POST /orders")
String createOrder(Order order);

@RequestLine("PUT /orders")
String updateOrder(Order order);

@RequestLine("DELETE /orders/{id}")
String deleteOrder(@Param("id") int id);

default List getOrders(int... ids) {
List orders = new ArrayList<>();
for (int id : ids) {
orders.add(this.getOrder(id));
}
return orders;
}
}

Tương tự Retrofit, chúng ta có thể sử dụng Interceptor – một tính năng của OkHttp để tự động thêm Authentication Token vào mỗi request, chúng ta không cần thêm nó một cách thủ công trong từng request.

Có một vài cách để gửi Authentication Header token lên server: sử dụng @Header, tạo custom Target, sử dụng Interceptor của Feign, sử dụng Interceptor của OkHttp.

Ví dụ bên dưới sử dụng 2 Interceptor:

  • AuthInterceptor : thêm Token vào mỗi request.
  • LoggingInterceptor : log trước khi gửi request và sau khi nhận response.

AuthInterceptor.java

package com.gpcoder.interceptor;

import java.io.IOException;

import com.gpcoder.helper.FeignClientCreator;
import com.gpcoder.service.AuthService;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class AuthInterceptor implements Interceptor {

private static String token = null;

@Override
public Response intercept(Chain chain) throws IOException {
/*
* chain.request() returns original request that you can work with(modify,
* rewrite)
*/
Request originalRequest = chain.request();

// Here we can rewrite the request
// We add an Authorization header if the request is not an authorize request and already had a token
Request authRequest = originalRequest;
if (!originalRequest.url().toString().contains("/auth") && getToken() != null) {
authRequest = originalRequest.newBuilder()
.header("Authorization", "Bearer " + getToken())
.build();
}

/*
* chain.proceed(request) is the call which will initiate the HTTP work. This
* call invokes the request and returns the response as per the request.
*/
Response response = chain.proceed(authRequest);

// Here we can rewrite/modify the response

return response;
}

private String getToken() throws IOException {
if (token != null) {
return token;
}

// Create an implementation of the API endpoints defined by the service interface
AuthService authService = FeignClientCreator.getService(AuthService.class);

// Sends a request to a webserver and return its response
return authService.getToken("gpcoder", "gpcoder");
}
}

Tương tự chúng ta sẽ tạo LoggingInterceptor:

LoggingInterceptor.java

package com.gpcoder.interceptor;

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();

long t1 = System.nanoTime();
System.out.println(
String.format("Sending request %s on %s%n%s", request.url(), chain.connection(), request.headers()));

Response response = chain.proceed(request);

long t2 = System.nanoTime();
System.out.println(String.format("Received response for %s in %.1fms%n%s", response.request().url(),
(t2 - t1) / 1e6d, response.headers()));

return response;
}
}

Để sử dụng Interceptor, chúng ta cần đăng ký với Client thông qua phương thức addInterceptor() hoặc addNetworkInterceptor(). Chương trình bên dưới, tôi đăng ký AuthInterceptor ở mức Application và LoggingInterceptor cho cả 2 mức Application và Network.

Chúng ta sẽ tạo một lớp hỗ trợ cấu hình Feign, đăng ký các Interceptor và tạo instance của Feign service.

FeignClientCreator.java

package com.gpcoder.helper;

import com.gpcoder.interceptor.AuthInterceptor;
import com.gpcoder.interceptor.LoggingInterceptor;
import com.gpcoder.service.OrderService;

import feign.Feign;
import feign.Logger;
import feign.form.FormEncoder;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import feign.okhttp.OkHttpClient;
import feign.slf4j.Slf4jLogger;

public class FeignClientCreator {

public static final String BASE_URL = "http://localhost:8080/RestfulWebServiceExample/rest/";

public static  T getService(Class clazz) {
okhttp3.OkHttpClient okHttpClient = new okhttp3.OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.addInterceptor(new AuthInterceptor())
.addNetworkInterceptor(new LoggingInterceptor())
.build();

OkHttpClient feignOkHttp = new OkHttpClient(okHttpClient);

return Feign.builder()
.client(feignOkHttp)
.encoder(new FormEncoder(new GsonEncoder()))
.decoder(new GsonDecoder())
.logger(new Slf4jLogger(clazz))
.logLevel(Logger.Level.FULL)
.target(clazz, BASE_URL);
}
}

Tiếp theo chúng ta sẽ sử dụng Feign service để call các API.

FeignClientExample.java

package com.gpcoder;

import java.io.IOException;

import com.gpcoder.helper.FeignClientCreator;
import com.gpcoder.model.Order;
import com.gpcoder.service.OrderService;

public class FeignClientExample {

private static OrderService orderService;

public static void main(String[] args) throws IOException {
orderService = FeignClientCreator.getOrderService(OrderService.class);

createOrder();
retrieveOrder();
updateOrder();
deleteOrder();
retrieveOrders();
}

/**
* @POST http://localhost:8080/RestfulWebServiceExample/rest/orders
*/
private static void createOrder() throws IOException {
System.out.println("createOrder: " + orderService.createOrder(new Order()));
}

/**
* @GET http://localhost:8080/RestfulWebServiceExample/rest/orders/1
*/
private static void retrieveOrder() throws IOException {
System.out.println("retrieveOrder: " + orderService.getOrder(1));
}

/**
* @PUT http://localhost:8080/RestfulWebServiceExample/rest/orders
*/
private static void updateOrder() throws IOException {
System.out.println("updateOrder: " + orderService.updateOrder(new Order()));
}

/**
* @DELETE http://localhost:8080/RestfulWebServiceExample/rest/orders/1
*/
private static void deleteOrder() throws IOException {
System.out.println("deleteOrder: " + orderService.deleteOrder(1));
}

private static void retrieveOrders() {
System.out.println("retrieveOrders: " + orderService.getOrders(1, 2));
}
}

Như bạn thấy, Feign là một thư viện rất mạnh mẽ nhưng rất đơn giản để sử dụng. Hy vọng bài viết giúp ích cho các bạn, hẹn gặp lại ở các bài viết tiếp theo.

Tài liệu tham khảo:

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm công việc CNTT hấp dẫn trên TopDev

Todo list: Khái niệm Laravel Controller

laravel controller
Todo list: Khái niệm Laravel Controller

Bài viết được sự cho phép của tác giả Kien Dang Chung

Video trong bài viết

Trong bài trước chúng ta đã sơ lược về mô hình MVC, bạn cũng đã được làm quen với Route và View. Trong bài hôm nay, bạn hãy cùng tôi tìm hiểu về Controller, vậy Laravel Controller có phải là Controller trong mô hình MVC, nó được sử dụng cho mục đích gì?.

Mô hình MVC

Laravel Controller

Chúng ta cùng xem định nghĩa Laravel Controller trên tài liệu chính thức của Laravel: Thay vì định nghĩa tất cả các đoạn xử lý logic nghiệp cho yêu cầu trong các file route dưới dạng Closure, chúng ta sẽ tổ chức nó vào các class Controller. Controller giúp nhóm các logic nghiệp vụ cho yêu cầu liên quan vào trong một class. Controller được lưu trong thư mục app/Http/Controllers. Như vậy chúng ta có thể thấy Laravel Controller mang dáng dấp của Controller trong MVC, tuy nhiên nó được phân lớp nhiều hơn, giúp xây dựng ứng dụng tốt hơn.

Khá rối rắm đúng không, bạn không cần quan tâm sâu bên trong, chỉ cần nhớ Controller trong Laravel là các class PHP nằm trong thư mục app/Http/Controllers, về chức năng chúng ta sẽ tìm hiểu dưới đây. Các controller này có thể tạo ra thủ công bằng cách tạo file hoặc thông qua câu lệnh artisan:

php artisan make:controller AboutController --resource

Ở đây, AboutController là tên controller, tham số –resource là tùy chọn, tham số này sẽ tạo ra controller với đầy đủ các phương thức cần thiết như index, create, store, update…

  Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream
  Cách sử dụng Laravel với Socket.IO

Xem thêm tuyển dụng Laravel nhiều vị trí trên TopDev

Một chú ý nữa là các file controller được tạo ra này sẽ có namespace theo đường dẫn thư mục đến controller. Ví dụ đường dẫn thư mục là app->Http->Controllers thì namespace ở đây sẽ là:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class AboutController extends Controller
{

}

Nhờ đó, Composer với autoloading có thể tải chính xác class này ngay khi bạn tạo ra nó. Chúng ta sẽ tìm hiểu về cách sử dụng của Controller.

Bạn có nhớ chúng ta đã khai báo đường dẫn about trong routes/web.php trong bài trước:

Route::get('about', function () {
    return view('about');
});

Tham số thứ hai của phương thức get() có thể là một function ở dạng Closure, ngoài ra nó có thể là một chuỗi bao gồm tên của controller và tên của phương thức trong controller cách nhau bởi ký tự @:

Route::get('about', 'AboutController@index');

Nếu bạn thực hiện luôn sẽ gặp lỗi “Method index doesn’t exist”, do phương thức index không tồn tại trong AboutController. Thêm phương thức index vào:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class AboutController extends Controller
{
    public function index()
    {
      return view('about');
    }
}

Quay lại trang http://localhost:8000/about mọi thứ hoạt động bình thường giống như khi chúng ta sử dụng kiểu Closure.

Trong phương thức của controller chúng ta có thể thực hiện rất nhiều công việc như gọi đến một api ở ngoài, thực hiện truy vấn cơ sở dữ liệu hoặc trả về một view như ví dụ ở trên.

Diễn giải một chút về hoạt động của ứng dụng:

  1. Người dùng vào đường dẫn http://localhost:8000/about
  2. Hệ thống kiểm tra trong routes/web.php xem đã định nghĩa chưa, nếu chưa trả về lỗi 404 không tìm thấy yêu cầu, nếu đã định nghĩa thực hiện tiếp nội dung trong tham số thứ 2 có thể là function dạng Closure hoặc chuỗi tên controller và phương thức trong đó, ở đây là ‘AboutController@index’.
  3. AboutController sẽ được tải lên và thực thi phương thức index().
  4. Phương thức index() trả về View about.blade.php tạo ra ở bài trước.
  5. Laravel Blade sẽ xử lý nội dung file blade và trả về người dùng nội dung thuần HTML.

Tóm tắt

Như vậy, sau bài học hôm nay bạn chỉ cần nắm được:

  • Laravel Controller là class PHP nằm trong app->Http->Controllers.
  • Nó có thể tạo thủ công hoặc bằng công cụ artisan.
  • Khi xử lý Route, có thể truyền vào một function hoặc một Controller.
  • Trong phương thức của controller có thể thực hiện bất cứ công việc nào có liên quan đến việc cuối cùng là trả về View.

Code: Bài 3 – Laravel Controller

Các bước thực hiện để chạy code giống 2 bài học trước.

Bài viết gốc được đăng tải tại allaravel.com

Có thể bạn quan tâm:

Xem thêm tuyển dụng CNTT hấp dẫn trên TopDev

Chia sẻ kinh nghiệm sử dụng trình duyệt web an toàn

sử dụng web an toàn
Chia sẻ kinh nghiệm sử dụng trình duyệt web an toàn

Bài viết được sự cho phép của blogchiasekienthuc.com

Trình duyệt Web (Microsoft Edge, Google Chrome, Cốc Cốc, Firefox, …) là một trong những cửa ngõ quan trọng (nếu không muốn nói là quan trọng nhất) khi chúng ta truy cập vào Internet.

Nó quan trọng như cánh cửa nhà bạn vậy, việc bạn sử dụng trình duyệt Web không an toàn cũng tương tự như việc bạn đi ngủ mà không đóng cửa vậy. Và chuyện gì xảy ra sau đó thì chắc có lẽ bạn cũng đoán được rồi, thậm chí còn hơn thế nữa là đằng khác.

Và dưới đây là 8 nguyên tắc an toàn mà bạn nên thực hiện khi sử dụng trình duyệt Web, hãy lưu ý kỹ thật kỹ nha các bạn.

  10 Java Web Framework tốt nhất
  10 trang web hàng đầu để tìm hiểu WordPress

Xem thêm tuyển web developer hấp dẫn trên TopDev

#1. Đăng xuất tất cả các tài khoản ngay sau khi sử dụng

Phần lớn các dịch vụ trên Internet như thư điện tử, mạng xã hội, hội thoại trực tuyến, diễn đàn, sàn thương mại điện tử, ngân hàng điện tử, … đều yêu cầu đăng nhập tài khoản trước khi sử dụng.

Nguyên tắc đầu tiên mà bạn cần ghi nhớ đó là, hãy đăng xuất tài khoản ngay sau khi sử dụng xong – nếu đó không phải là máy tính cá nhân của bạn.

Việc không đăng xuất tài khoản ngay sau khi sử dụng xong sẽ là một điều tai hại cho nhiều người dùng. Chưa nói đến các Hacker mũ đen, chỉ cần là người có chút hiểu biết về Công nghệ thông tin là họ đã có thể chiếm đoạt được tài khoản của bạn rồi.

Ngoài ra, khi trình duyệt Web xuất hiện hộp thoại “Bạn có muốn lưu mật khẩu không?” thì bạn nên chọn “Không bao giờ” nhé, vì người dùng có thể dễ dàng lấy được thông tin tài khoản trong phần quản lý của trình duyệt web.

cach-su-dung-trinh-duyet-web-an-toan (1)

Có một giải pháp hữu hiệu giúp bạn dễ dàng thực hiện nguyên tắc này là hãy sử dụng chế độ duyệt ẩn danh khi sử dụng máy tính công cộng. Hoặc sử dụng chế độ Guest (khách) trên Chrome (nếu bạn sử dụng Google Chrome).

=> Bởi khi sử dụng chế độ duyệt web này thì ngay cả khi bạn tắt trình duyệt nhưng quên không thoát tài khoản thì nó vẫn không bị lưu lại.

Mình luôn sử dụng chế độ này khi sử dụng các máy tính công cộng (như là ở thư viện, cửa hàng dịch vụ truy cập Internet, cửa hàng Photocopy, …)

Để mở nhanh chế độ duyệt web ẩn danh bạn hãy nhấn tổ hợp phím Ctrl + Shift + N nhé. Rất đơn giản thôi thông có gì phức tạp cả.

#2. Không đăng nhập vào tài khoản Google khi sử dụng Google Search

Rất nhiều bạn có thói quen là đăng nhập vào tài khoản Google trong khi sử dụng công cụ tìm kiếm Google Search.

Chúng ta không nên làm như vậy, dựa vào những gì bạn tìm kiếm thì Google sẽ có cái tổng thể về bạn, đôi khi Google hiểu bạn còn nhiều hơn gia đình bạn hiểu bạn.

cach-su-dung-trinh-duyet-web-an-toan (2)

Hầu hết chúng ta ít hay nhiều đều có bí mật, đã là bí mật mà để cho “người khác” biết thì thực sự không tốt chút nào. Trong trường hợp đặc biệt bạn không có bí mật thì cũng không nên đăng nhập, bởi những gì bạn tìm kiếm có thể trở thành mục tiêu của quảng cáo.

Vậy nên bạn có thể tìm kiếm với web ẩn danh hoặc trong chế độ Guest. Thao tác chưa đến 1 giây đâu các bạn, nhiều khi nói ra thì các bạn bảo là rườm rà với phức tạp, nhưng thực tế thì gần như không tốn thêm thời gian. Nó là thói quen thôi !

#3. Ẩn danh địa chỉ IP bằng cách sử dụng VPN

Hiểu một cách đơn giản thì địa chỉ IP chính là địa chỉ nhà của bạn trên Internet

Trình duyệt web bạn sử dụng, trang web bạn đang truy cập và các nhà cung cấp dịch vụ Internet mà bạn đang dùng sẽ biết được địa chỉ IP của bạn. Bạn không thể ẩn hoàn toàn địa chỉ IP của mình, vì chúng ta cần nó để giao tiếp với Internet.

Tuy nhiên, chúng ta có thể sử dụng VPN để ẩn danh địa chỉ IP (tức là tạo ra một dải địa chỉ IP giả hay còn gọi là Fake IP), hiện tại có khá nhiều nhà cung cấp dịch vụ VPN nổi tiếng, dưới đây là các nhà cung cấp uy tín mà các bạn có thể tham khảo:

  • StrongVPN
  • Hostpot Sheild
  • CyberGhost VPN
  • F-Secure Freedome
  • Ngoài ra thì bạn có thể tham khảo trong chuyên mục này nhé, có link tải và hướng dẫn rất chi tiết cho từng phần mềm.

cach-su-dung-trinh-duyet-web-an-toan (3)

#4. Cập nhật trình duyệt web ngay khi có phiên bản mới

Các phần mềm mà bạn vẫn đang sử dụng hằng ngày được tạo ra từ hàng nghìn, thậm chí hàng triệu dòng lệnh khác nhau. Trước khi xuất bản, các lập trình viên đều đã kiểm tra một cách rất cẩn thận nhưng vẫn không thể tránh được những sai sót.

Không có gì là hoàn hảo cả, bạn biết điều này mà đúng không. Nhất là đối với những phần mềm có nhiều người dùng, vì đây sẽ là mục tiêu mà hacker hướng đến nhiều nhất.

Vậy nên, nếu là một phần mềm được đầu tư bài bản thì nhà phát triển họ sẽ phát hành các bản cập nhật định kỳ (có thể là hàng tháng hoặc hằng năm), bản cập nhật có thể là các bản vá lỗi, vá các lỗ hổng bảo mật, hoặc là bổ sung thêm các tính năng mới cho phần mềm.

Vâng, và trình duyệt web cũng là một phần mềm, không những thế nó còn là cánh cửa để máy tính kết nối với Internet. Chính vì vậy, việc đảm bảo cho các trình duyệt luôn được cập nhật phiên bản mới nhất là một trong những việc rất nên làm.

Việc cập nhật cũng vô cùng đơn giản, đối với các trình duyệt web như Microsoft Edge, Google Chrome, hay Cốc Cốc đều tự động làm điều này với các cài đặt mặc định. Bạn có thể kiểm tra phiên bản của 3 trình duyệt Web trên bằng cách nhập sử dụng tương ứng:

edge://settings/help hoặc chrome://settings/help hoặc coccoc://settings/help

cach-su-dung-trinh-duyet-web-an-toan (4)

#5. Tắt Cookie nếu không thực sự cần thiết

Cookie là một file tạm được tạo ra một cách tự động khi bạn truy cập vào một trang web bất kỳ. Lúc này, Cookie sẽ lưu lại toàn bộ thông tin của bạn như là tài khoản cá nhân, lịch sử truy cập các trang web, thiết bị mà bạn dùng để lướt web..

Tìm hiểu kỹ hơn về Cookie tại đây !

Trên lý thuyết thì Cookie vô hại, nó được sử dụng để mang lại những trải nghiệm tốt hơn, liền mạch hơn.

Tuy nhiên nó đã và đang bị lợi dụng, chủ yếu là để khai thác quảng cáo và bán cho các nhà quảng cáo. Vì vậy chúng ta nên hạn chế hoặc tắt Cookie đi nếu bạn cảm thấy không thực sự cần thiết.

Tùy thuộc vào trình duyệt web bạn sử dụng mà chúng ta sẽ có cách truy cập vào trình quản lý Cookie tương ứng:

Trình duyệt Địa chỉ truy cập nhanh
Edge edge://settings/content/cookies
Chrome chrome://settings/cookies
Cốc Cốc coccoc://settings/cookies

cach-su-dung-trinh-duyet-web-an-toan (5)

#6. Cẩn thận với WiFi công cộng và WiFi không yêu cầu mật khẩu đăng nhập

Các WiFi miễn phí thường không yêu cầu mật khẩu đăng nhập, chúng thường được cung cấp miễn phí tại những nơi tập trung đông người như sân bay, nhà ga, công viên, phố đi bộ, …

Việc không yêu cầu mật khẩu đăng nhập giúp chúng ta truy cập dễ dàng hơn, tuy nhiên nếu không cẩn thận thì rất có thể bạn sẽ thể truy cập nhầm vào các mạng WiFi giả mạo.

Wifi giả mạo thường được tạo ra để thực hiện những mục đích xấu xa, một trong những mục đích thường thấy là thu thập thông tin và đánh cắp tài khoản trực tuyến, tài khoản ngân hàng của bạn.

cach-su-dung-trinh-duyet-web-an-toan (6)

Cá nhân mình thì rất hạn chế sử dụng mạng Wifi miễn phí và không bao giờ đăng nhập các tài khoản quan trọng như ngân hàng điện tử, Google Account hoặc thực hiện các giao dịch tài chính với mạng WiFi công cộng này.

Trong trường hợp bất khả kháng mà bạn thường xuyên phải sử dụng WiFi miễn phí thì giải pháp hữu hiệu nhất chính là sử dụng VPN (phần mềm Fake IP).

Đọc thêm bài viết: Duyệt Web an toàn và riêng tư với F-Secure Freedome (có trong serie này nhé) !

#7. Kiểm tra các quyền đi kèm với các trang web

Một số trang web khi truy cập sẽ yêu cầu cung cấp một hoặc một số quyền như:

  • Vị trí (sàn thương mại điện tử, dịch vụ bản đồ trực tuyến, …)
  • Micro và / hoặc Webcam (Messenger, Zalo, Google Meet, Microsoft Teams, …)

Tùy thuộc vào nhu cầu cụ thể mà chúng ta lựa chọn Cho phép hoặc Chặn, nhưng cần chú ý là chỉ cấp quyền cho những trang web chính thống, những trang web đáng tin tưởng thôi các bạn nhé.

Thông báo yêu cầu cấp quyền truy cập sẽ suất hiện ở góc trên bên trái của trình duyệt Web.

cach-su-dung-trinh-duyet-web-an-toan (7)

#8. Cẩn thận mỗi khi click chuột vào các liên kết

Xem xét, thận trọng trước khi nháy chuột vào các liên kết không rõ nguồn gốc.

Đôi khi trong hộp thư đến, chúng ta sẽ nhận một số thư có tiêu đề kiểu “Tài khoản của bạn đã bị khóa, nháy chuột vào liên kết và làm theo hướng dẫn để khôi phục”, “Bạn là khách hàng may mắn nhất của ngày hôm nay, nháy chuột vào liên kết và làm theo hướng dẫn để nhận thường”, …

Hấu hết chúng đều là lừa đảo, nếu bạn làm theo thì nhiều khả năng bạn sẽ bị khóa / mất tài khoản hoặc bị mất tiền (lúc này mới là thật) (^-^)

Khi gặp một liên kết đáng nghi thì bạn có thể sử dụng công cụ VirusTotal quét qua từ đó có thêm thông tin để đưa ra quyết định chính xác.

cach-su-dung-trinh-duyet-web-an-toan (8)

#9. Lời kết

Nhìn chung thì các sự cố về an toàn thông tin xảy ra, nguyên nhân chủ yếu đến từ phía người dùng là chính.

Qua bài viết này thì mình đã chia sẻ đến các bạn khá nhiều lời khuyên hữu ích và thực tế, bạn cũng có thể xem đây là các chỉ dẫn để sử dụng trình duyệt web một cách an toàn hơn nhé.

Thời gian đầu bạn nên cố gắng thực hiện theo, lâu dần nó sẽ trở thành một thói quen tốt, khi đó bạn sẽ không bao giờ quên và tất nhiên là lúc này bạn có thể thực hiện một cách dễ dàng mà không cần cố gắng nữa. Xin chào tạm biệt và hẹn gặp lại các bạn trong những bài viết tiếp theo !

CTV: Nhựt Nguyễn – Bài viết gốc được đăng tải tại blogchiasekienthuc.com

Có thể bạn quan tâm:

Xem thêm tuyển dụng CNTT hấp dẫn trên TopDev

Tổng Hợp Các Công Ty Outsourcing Lớn Nhất Việt Nam

các công ty outsourcing lớn nhất việt nam
Tổng Hợp Các Công Ty Outsourcing Lớn Nhất Việt Nam

Hiện nay, để tối ưu chi phí nhưng vẫn duy trì được hoạt động của công ty, rất nhiều doanh nghiệp đang lựa chọn hình thức outsourcing. Việc sử dụng công ty outsourcing sẽ giúp các công ty có được sản phẩm mình ưng ý nhất mà không phải tốn quá nhiều nhân sự cho công việc. Cùng tìm hiểu thêm các công ty outsourcing lớn nhất Việt Nam trên thị trường.

các công ty outsourcing lớn nhất việt nam

*Số thứ tự trong bài viết chỉ nhằm liệt kê các công ty, không nhằm mục đích xếp hạng hay đánh giá

1. FPT Software – ra đời với mục tiêu gia công phần mềm để đáp ứng cho nhu cầu phát triển công nghệ thông tin của các hãng phần mềm, các công ty lớn trong nước và tham vọng hơn là xuất khẩu phần mềm trên toàn thế giới cho các công ty nước ngoài.

2. NASHTECH – mục đích đẩy mạnh việc sử dụng các công nghệ tiên tiến trong các lĩnh vực như điện toán đám mây, dữ liệu lớn và an ninh mạng vốn là thế mạnh của NashTech.

3. KMS Technology – chuyên cung cấp các dịch vụ phát triển phần mềm, tư vấn triển khai các giải pháp công nghệ, khởi nghiệp và đầu tư.

4. Tek Experts – cung cấp các gói dịch vụ hỗ trợ kinh doanh về IT

5. Netcompany

6. TMA Solutions – công ty outsourcing có thâm niên hoạt động khá lâu năm và uy tín.

7. Hitachi Vantara Vietnam (tên cũ Global CyberSoft) – cung cấp dịch vụ và giải pháp công nghệ thông tin hàng đầu Việt Nam

8. Fram^ – IT Engineering & Venture Building

9. Axon Active – tiên phong trong lĩnh vực phát triển phần mềm offshore và có trụ sở tại Thụy Sỹ

10. Accenture – tư vấn quản lý, dịch vụ công nghệ và gia công phần mềm toàn cầu

11. Open Web Technology tuyển dụng

12. Orient Software Development Corp – chuyên phát triển phần mềm và trang web ra nước ngoài

13. ELCA Việt Nam – phát triển sản xuất phần mềm theo mô hình offshore

14. Savvycom – nhà cung cấp các dịch vụ về công nghệ thông tin hàng đầu tại Việt Nam

15. QSoft Việt Nam – cung cấp đa dạng các giải pháp về CNTT cho các doanh nghiệp

16. Tinhvan Group (Công ty Cổ phần Xuất khẩu Phần mềm Tinh Vân) – kinh nghiệm chuyên sâu trong việc triển khai các dự án gia công PM thuộc nhiều lĩnh vực khác nhau.

17. Rikkeisoft – một trong những công ty hàng đầu tại Việt Nam về sản xuất phần mềm, đặc biệt là ứng dụng trên nền tảng web và smartphone

18. Ominext – cung cấp giải pháp và tích hợp hệ thống thông tin Y tế cho đối tác Nhật Bản

19. THL ONE tuyển dụng

20. E-GROUPS VIỆT NAM hay còn gọi là công ty TNHH TMDV EG Việt Nam với nhiệm vụ chính là xây dựng phần mềm tại Việt Nam và nước ngoài.

21. BrickMate Group

22. Ant-Tech – chuyên nhận các dự án thiết kế ứng dụng từ các khách hàng ở Pháp và châu Âu.

Trên đây là thông tin về một số các công ty outsourcing lớn nhất Việt Nam mà bạn có thể tham khảo. Tìm hiểu thêm về các thông tin hấp dẫn khác tại topdev.vn/blog


Tuyển Dụng Nhân Tài IT Cùng TopDev
Đăng ký nhận ưu đãi & tư vấn về các giải pháp Tuyển dụng IT & Xây dựng Thương hiệu tuyển dụng ngay!
Hotline: 028.6273.3496 – Email: contact@topdev.vn
Dịch vụ: https://topdev.vn/page/products

3 cách cài đặt tiện ích mở rộng (plugin) trên WordPress

cài đặt plugin
3 cách cài đặt tiện ích mở rộng (plugin) trên WordPress

Bài viết được sự cho phép của blogchiasekienthuc.com

WordPress là một trong những mã nguồn mở được sử dụng để xây dựng website phổ biến nhất trên thế giới hiện nay. Theo thống kê thì có tới gần 36% website trên Internet được xây dựng bằng mã nguồn WordPress. Dành cho bạn nào chưa biết thì blog mà bạn đang đọc đây cũng được xây dừng bằng mã nguồn mở này ^^

WordPress sẽ giúp bạn tạo một trang web đơn giản, nhưng nhờ có kho tiện ích mở rộng (hay còn gọi là plugin) đồ sộ mà người dùng có thể thỏa sức tùy biến theo các nhu cầu riêng, bạn có thể thêm nhiều chức năng khác như đánh giá bài viết, bình luận bài viết, trang bán hàng, thương mại điện tử cỡ nhỏ…

Tuy việc cài đặt các plugin trên WordPress là vô cùng đơn giản, thế nhưng nếu bạn không kiểm tra cẩn thận thì rất có thể gây xung đột cho cả hệ thống website. Vâng, và tất nhiên là trong bài viết này mình sẽ hướng dẫn cho các bạn 3 cách cài đặt plugin trên website WordPress đơn giản nhất.

Xem thêm tuyển dụng WordPress lương cao trên TopDev

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-1-min

I. Cách cài đặt tiện ích mở rộng trên WordPress

// Bài viết này áp dụng cho cả WordPress trên Localhost lẫn WordPress trên hosting hoặc VPS nhé các bạn.

Trên WordPress có 2 loại tiện ích mở rộng (plugin) MIỄN PHÍ và TRẢ PHÍ. Các plugin miễn phí thì bạn có thể vào trực tiếp kho plugin để cài đặt, vô cùng đơn giản và nhanh chóng.

Còn đối với loại plugin trả phí thì các bạn sẽ phải mua bản quyền trên các chợ thường là Envato Elements hoặc là mua trực tiếp từ trang của nhà phát triển => rồi cài đặt theo cách thủ công.

Có rất nhiều chợ bán plugin và theme, phần lớn các plugin hiện nay đều do người dùng là các lập trình viên viết ra chứ không phải do đội ngũ phát triển của WordPress. Chính vì thế nên lại nảy sinh thêm vấn đề tương thích giữa các plugin. Nhưng bạn cũng không cần phải quá lo lắng, bạn chỉ cần để ý xíu trong việc lựa chọn plugin là được.

Từ trang quản trị của WordPress, bạn chọn phần Plugins ở thanh điều hướng bên trái màn hình để vào phần quản lý tiện ích mở rộng, nó sẽ là Công cụ nếu bạn cài ngôn ngữ tiếng Việt cho WordPress.

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-2-min

Tại đây, bạn có thể biết được những plugin nào đã được cài đặt trên trang web của mình, do ở đây mình cũng vừa mới setup xong nên cũng chưa có nhiều plugin lắm.

Các plugin có nền màu xanh như LiteSpeed Cache trong hình nghĩa là đang được bật, bạn có thể click Deactive để tắt nếu plugin gặp vấn đề hoặc gây lỗi website.

Còn các plugin nền trắng nghĩa là đang tắt, click vào Active để bật chúng lên. Ngoài ra, nếu Plugin nào đó có bản update mới thì cũng sẽ có thông báo hiện lên ở đây và bạn có thể chọn có cập nhật hay là không.

Sau khi kích hoạt xong nếu bạn không muốn sử dụng Plugin đó nữa thì có thể nhấn vào Delete để xóa hẳn Plugin đó đi, hoặc nhấn vào Deactivate để ngưng kích hoạt.

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-9-min

Cách #1: Cài đặt plugin từ kho plugin có sẵn của WordPress

Từ trang quản lý plugin bạn bấm vào nút Add New để tiến hành cài một tiện ích mở rộng mới. Trang Add Plugins xuất hiện ngay sau đó và hiển thị một số plugin tiêu biểu nhất mà bạn có thể cài.

Đa số các plugin trên đây đều miễn phí và số lượng cực kỳ nhiều, thoải mái sử dụng. Nếu các plugin được hiển thị không phù hợp với nhu cầu, bạn có thể nhập từ khóa vào ô Search plugins ở bên phải để tìm.

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-3-min

Bên dưới mỗi plugin đều hiển thị lượt cài đặt, cũng như đánh giá của người dùng giúp chúng ta biết có nên sử dụng plugin đó hay không. Lần cập nhật Plugin gần đây nhất cũng là thông tin bạn nên để ý, nếu plugin đã quá lâu không được cập nhật lên phiên bản mới thì cũng hạn chế sử dụng, vì có thể tác giả đã không còn quan tâm đến nó nữa rồi.

Ngoài ra, một số plugin sẽ chỉ tương thích với một số phiên bản WordPress nhất định, vậy nên nếu plugin bạn muốn cài có dòng Compatible with your version of WordPress thì nghĩa là plugin đó tương thích với phiên bản WordPress bạn đang sử dụng, và bạn có thể cài vào sử dụng bình thường, còn không thì đừng nên cài nhé.

Giờ để cài đặt plugin bất kỳ, bạn hãy click vào nút Install Now và quá trình cài đặt sẽ diễn ra tự động ngay sau đó.

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-4-min

Mặc định plugin khi mới cài xong sẽ ở trạng thái chưa kích hoạt, bạn phải bật thủ công bằng cách bấm vào nút Activate hoặc quay lại trang quản lý Plugin ở trên rồi chọn Active. Vậy là xong, rất đơn giản !

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-5-min

  12 plugin nên dùng trong Adobe XD
  11 cách tăng tốc nhanh cho WordPress bằng file wp-conig.php

Cách #2: Cách cài plugin thủ công, cài plugin bản quyền

Thường cách cài thủ công này chỉ áp dụng với các plugin bạn mua trên các chợ ứng dụng, không có sẵn trên kho plugin miễn phí. Bạn cần lưu ý, đọc kỹ thông tin để đảm bảo nó không bị xung đột với các plugin khác, hoặc không tương thích với phiên bản WordPress đang sử dụng.

Sau khi thanh toán hoàn tất và bạn đã tải plugin mới mua về, bạn sẽ nhận được tệp chứa bộ cài dạng *.ZIP trùng với tên plugin và phần hướng dẫn sử dụng của plugin đó tương tự như hình bên dưới. Phần documentation bạn có thể xem qua để biết cách thiết lập plugin như thế nào, giờ hãy giải nén những file này ra để tiến hành cài đặt.

NOTE: Giải nén để lấy file *.zip bên trong nhé bạn, như ví dụ ở đây là mình giải nén ra để lấy file tm-progress-loader.zip đó các bạn.

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-6-min

Quay lại trang Add Plugins giống như Cách #1 bên trên, bạn bấm vào nút Upload Plugins. Phần tải lên hiện ra, bạn bấm Choose File và chọn đường dẫn đến file ZIP đã giải nén trước đó và cuối cùng bấm Install Now để cài đặt.

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-7-min

Quá trình cài đặt hoạt tất, bạn có thể bấm vào nút Active Plugin để kích hoạt luôn plugin vừa cài, hoặc chọn Go to Plugin Installer để cài tiếp plugin khác. Tiếc là WordPress hiện không hỗ trợ cài nhiều plugin cùng một lúc.

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-8-min

Trường hợp gặp lỗi, thường là do dung lượng của plugin bạn muốn cài đặt lớn hơn dung lượng tải lên cho phép của Web Server, mặc định là 2MB. Cái này cũng không có gì nghiêm trọng, bạn chỉ cần sửa lại thông số upload_max_filesize trong phần cài đặt PHP của hosting hoặc sửa trực tiếp trong file php.ini cũng được.

Nếu không biết làm, bạn có thể nhờ bộ phần kỹ thuật của nhà cung cấp hosting mà bạn đang sử dụng nhé, rất nhanh thôi.

Cách #3. Cách này dành cho hosting hoặc VPS

Bạn login và Hosting hoặc VPS mà bạn quản lý, ví dụ ở đây mình sẽ sử dụng phần mềm Bitvise SSH Client để login vào VPS.

=> Sau đó bạn truy cập theo địa chỉ này: ……pubic_html/wp-content/plugin

cach-cai-dat-plugin-tren-wordpress

Rồi tiến hành upload file plugin *.zip đó lên => rồi giải nén ra. Sau cùng bạn vào lại phần Plugins để kích hoạt Plugin mà bạn vừa tải lên là xong.

huong-dan-cai-dat-tien-ich-mo-rong-tren-wordpress-2-min

II. Lời kết

Như vậy là mình đã vừa hướng dẫn xong cho các bạn 3 cách để cài đặt plugin trên WordPress phổ biến và đơn giản nhất hiện nay rồi nhé. Đây là những cách thường được sử dụng nhất và bạn cũng nên thành thạo nó để không gặp khó khăn khi dùng hệ thống CMS vô cùng mạnh mẽ này ha.

CTV: Nguyễn Thanh Tùng – Bài viết gốc được đăng tải tại blogchiasekienthuc.com

Có thể bạn quan tâm:

Xem thêm tuyển dụng CNTT hấp dẫn trên TopDev

Giới thiệu HATEOAS

Giới thiệu HATEOAS
Giới thiệu HATEOAS

Bài viết được sự cho phép của tác giả Giang Phan

1. HATEOAS là gì?

HATEOAS (Hypermedia AThe Engine OApplication State) là một trong những chuẩn được khuyến nghị cho RESTful API. Thuật ngữ “Hypermedia” có nghĩa là bất kỳ nội dung nào có chứa các liên kết (link) đến các media khác như image, movie và text.

Kiểu kiến trúc này cho phép bạn sử dụng các liên kết hypermedia trong nội dung response để client có thể tự động điều hướng đến tài nguyên phù hợp bằng cách duyệt qua các liên kết hypermedia. Nó tương tự như một người dùng web điều hướng qua các trang web bằng cách nhấp vào các link thích hợp để chuyển đến nội dung mong muốn.

HATEOAS mong muốn phía client không cần biết chút nào về cấu trúc phía server, client chỉ cần request đến một URL duy nhất, rồi từ đó mọi đường đi nước bước tiếp theo sẽ do chỉ dẫn của phía server trả về.

  "Mục tiêu và thách thức của Chatbot là hiểu được cảm xúc của người dùng và có cảm xúc riêng"
  10 ngôn ngữ phát triển nhanh nhất theo GitHub thống kê năm 2024

Xem thêm việc làm SSIS hấp dẫn trên TopDev

2. Ví dụ HATEOAS với JAX-RS

Giả sử chúng ta có một ứng dụng blog, một blog gồm nhiều bài viết, mỗi bài viết được viết bởi một tác giả nào đó. Ở mỗi bài viết có thể có nhiều bình luận và được đánh dấu một số tag. Sơ đồ class ở server như sau:

Hệ thống cung cấp các REST API cho ứng dụng blog được mô tả như sau:

  • @GET /articles : lấy danh sách thông tin tất cả các article.
  • @GET /articles/1 : lấy thông tin một article có id=1
  • @GET /articles/1/comments : lấy danh sách comment của một article có id=1
  • @GET /articles/1/tags: lấy danh sách tag của một article có id=1

Response trả về khi gọi @GET /articles :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[
    {
        "id": 1,
        "content": "HATEOAS example by gpcoder",
        "publishedDate": "14/07/2019",
        "authorId": 1
    },
    {
        "id": 2,
        "content": "HATEOAS example by gpcoder",
        "publishedDate": "14/07/2019",
        "authorId": 1
    },
    {
        "id": 3,
        "content": "HATEOAS example by gpcoder",
        "publishedDate": "14/07/2019",
        "authorId": 1
    }
]

Để lấy thông tin chi tiết của article, chúng ta sẽ gọi tiếp @GET /articles/ + id của article. Tương tự chúng ta cũng cần ghép chuỗi comments, tags để có URL lấy danh sách comments, tags.

Cách thiết kế này có vấn đề là chúng ta phải biết cấu trúc resource của server để gọi cho đúng. Nếu server thay đổi cấu trúc, phía client cũng phải thay đổi theo.

Bây giờ hãy xem cách HATEOAS giải quyết vấn đề này như sau:

  • JAX-RS cung cấp 2 class: UriInfo và Link builder để tạo ra các hypermedia Link.
  • Chúng ta có thể tạo tạo thêm một thuộc tính Link trong Model class để cung cấp hypermedia Link cho client hoặc gán trực tiếp chúng trong Header.

Article.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.gpcoder.model;
import javax.ws.rs.core.Link;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement
public class Article {
    private Integer id;
    private String content;
    private String publishedDate;
    private Integer authorId;
     private Link self;
}

ArticleService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package com.gpcoder.api;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import javax.annotation.security.PermitAll;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import com.gpcoder.model.Article;
// URI:
// http(s)://<domain>:(port)/<YourApplicationName>/<UrlPattern in web.xml>/<path>
@Path("/articles")
@PermitAll
public class ArticleService {
    
    @GET
    @Path("/")
    public Response getArticles(@Context UriInfo uriInfo) {
        List
<Article> articles = Arrays.asList(
            createArticle(1),
            createArticle(2),
            createArticle(3)
        );
        
        for (Article article : articles) {
            Link selfLink = Link.fromUri(uriInfo.getAbsolutePath().resolve(article.getId().toString())).rel("self").type("GET").build();
            article.setSelf(selfLink);
        }
        
        Link selfLink = Link.fromUri(uriInfo.getAbsolutePath()).rel("self").type("GET").build();
        
        Link nextLink = Link.fromUriBuilder(uriInfo.getAbsolutePathBuilder()
                .queryParam("page", "2"))
                .rel("next")
                .type("GET")
                .build();
        
        Link prevLink = Link.fromUriBuilder(uriInfo.getAbsolutePathBuilder()
                .queryParam("page", "0"))
                .rel("prev")
                .type("GET")
                .build();
        
        return Response.ok(articles).links(selfLink, nextLink, prevLink).build();
    }
    @GET
    @Path("/{id}")
    public Response getArticle(@PathParam("id") int id, @Context UriInfo uriInfo) {
        Article article = createArticle(id);
        Link selfLink = Link.fromUri(uriInfo.getAbsolutePath().resolve(article.getId().toString())).rel("self").type("GET").build();
        
        Link commentLink = Link.fromUriBuilder(uriInfo.getAbsolutePathBuilder()
                .path(article.getId().toString()).path("comments"))
                .rel("comments")
                .type("GET").build();
        
        Link tagLink = Link.fromUriBuilder(uriInfo.getAbsolutePathBuilder()
                .path(article.getId().toString()).path("tags"))
                .rel("tags")
                .type("GET").build();
        
        article.setSelf(selfLink);
        return Response.ok(article).links(selfLink, commentLink, tagLink).build();
    }
    
    private Article createArticle(Integer id) {
        Article article = new Article();
        article.setId(id);
        article.setContent("HATEOAS example by gpcoder");
        article.setPublishedDate(LocalDate.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
        article.setAuthorId(1);
        return article;
    }
    
    @GET
    @Path("?page={page}")
    public Response getArticles(@QueryParam("page") int page) {
        return null;
    }
    
    @GET
    @Path("/{id}/comments")
    public Response getComments(@PathParam("id") int id) {
        return null;
    }
    
    @GET
    @Path("/{id}/tags")
    public Response getTags(@PathParam("id") int id) {
        return null;
    }
}

Mở Postman để test kết quả:

@GET http://localhost:8080/RestfulWebServiceExample/rest/articles

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
[
    {
        "id": 1,
        "content": "HATEOAS example by gpcoder",
        "publishedDate": "14/07/2019",
        "authorId": 1,
        "self": {
            "params": {
                "rel": "self",
                "type": "GET"
            },
            "type": "GET",
            "rel": "self",
            "uriBuilder": {
                "absolute": true
            },
            "rels": [
                "self"
            ],
            "title": null
        }
    },
    {
        "id": 2,
        "content": "HATEOAS example by gpcoder",
        "publishedDate": "14/07/2019",
        "authorId": 1,
        "self": {
            "params": {
                "rel": "self",
                "type": "GET"
            },
            "type": "GET",
            "rel": "self",
            "uriBuilder": {
                "absolute": true
            },
            "rels": [
                "self"
            ],
            "title": null
        }
    },
    {
        "id": 3,
        "content": "HATEOAS example by gpcoder",
        "publishedDate": "14/07/2019",
        "authorId": 1,
        "self": {
            "params": {
                "rel": "self",
                "type": "GET"
            },
            "type": "GET",
            "rel": "self",
            "uriBuilder": {
                "absolute": true
            },
            "rels": [
                "self"
            ],
            "title": null
        }
    }
]

Như bạn thấy, ở mỗi article đều cung cấp link để truy xuất thông tin chi tiết của một article. Dựa vào đây chúng ta có thể gọi API tiếp mà không cần quan tâm cấu trúc resource trên server như thế nào.

Mở tab Headers, chúng ta có thông tin truy xuất các resource khác như phân trang: next, prev.

Tương tự: @GET http://localhost:8080/RestfulWebServiceExample/rest/articles/1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
    "id": 1,
    "content": "HATEOAS example by gpcoder",
    "publishedDate": "14/07/2019",
    "authorId": 1,
    "self": {
        "params": {
            "rel": "self",
            "type": "GET"
        },
        "type": "GET",
        "rel": "self",
        "uriBuilder": {
            "absolute": true
        },
        "rels": [
            "self"
        ],
        "title": null
    }
}

Như bạn thấy HATEOAS rất hữu dụng, tuy nhiên việc xử lý để tính toán ra những hành động, hyperlink tương ứng khá phức tạp và bandwidth dành cho nó cũng không dễ chịu chút nào. Hiện tại không có nhiều ứng cung cấp REST API với HATEOAS. Nếu không cần thiết, hãy hỗ trợ HATEOAS là optional thông qua header.

Tài liệu tham khảo:

Bài viết gốc được đăng tải tại gpcoder.com
Có thể bạn quan tâm:
Xem thêm tuyển dụng CNTT hấp dẫn trên TopDev

Làm quen với ZK framework

zk framework
Làm quen với ZK framework

Bài viết được sự cho phép của smartjob.vn

Chào các bạn! Trong bài viết này, chúng tôi giới thiệu một framework xây dựng ứng dụng doanh nghiệp là ZK framework. Điều kiện ban đầu: bạn đã nắm vững Java core, từng xây dựng ứng dụng web sử dụng Servlet, JSP. Có thể bạn đã rất thành thạo Apache Struts phiên bản 1 hoặc 2, có thể bạn đã từng xây dựng ứng dụng Rich Internet Application sử dụng GWT (Google Web Toolkit) hay Vaadin, v.v.. Nếu bạn chưa từng nghe đến hoặc chưa từng sử dụng ZK, bài viết này là dành cho bạn.

Xem thêm tuyển dụng Product Owner lương cao trên TopDev

Giới thiệu ZK Framework

ZK framework được phát triển bởi Potix Đài Loan cùng với cộng đồng lập trình viên mã nguồn mở. Triết lý của ZK là AJAX without Javascript, tức là lập trình viên Java server-side không cần quá tinh thông Javascript để tạo ra một ứng dụng web Java hoàn tất. Đặc trưng công nghệ của ZK framework là server-centric (các xử lý tập trung ở phía server-side). Điều này khác với triết lý công nghệ của nhóm bộ tam: GWT, Vaadin và ExtJS là client-centric (các xử lý tập trung ở phía client).

ZK có vài phiên bản khác nhau miễn phí và có trả phí. Mã nguồn của ZK là mã nguồn mở, bạn có thể xem, thậm chí là đóng góp (commit) vào mã nguồn của ZK thông qua GitHub. Phiên bản mới nhất hiện nay là ZK framework 8.x, với nhiều cải tiến về giao diện (bóng bẩy hơn), hiệu suất (performance) cao hơn. Có nhiều tiện ích hỗ trợ các component (hợp phần, mô đun) tiêu chuẩn như ZK Spreadsheet: bảng tính, ZK charts: Hỗ trợ rất nhiều loại biểu đồ trực quan. Ngoài ra các componet rất hay được sử dụng là ZK Calendar giúp xây dựng bảng chấm công, lịch trình, thời gian biểu. Có ZK Pivottable giúp hiển thị tập dữ liệu phức tạp, kích thước lớn.

Nói về tài liệu tra cứu, các ví dụ minh họa trực quan kèm mã nguồn rất phong phú. ZK giúp lập trình viên Java server-side xây dựng ứng dụng doanh nghiệp nhanh dạng Rich Internet Application. Bạn có thể xây dựng ứng dụng theo design pattern là MVVM hoặc MVC đều được.

  10 Java Web Framework tốt nhất
  .NET core vs ASP.NET core: Phân biệt .NET Framework, .NET Core và Mono

Chúng ta bắt đầu:

1. Bạn cài đặt JDK, Maven (xem hướng dẫn cài đặt: https://maven.apache.org/install.html ). Tôi kiểm tra môi trường như sau: Nếu gõ

ra kết quả, nghĩa là đã cài đặt môi trường phát triển và thiết lập biến môi trường Java đúng.
Nếu gõ

ra kết quả, nghĩa là đã cài đặt Maven và thiết lập biến môi trường thành công.

2. Khởi tạo project

Truy cập https://github.com/zkoss/zkessentials để tải về project khung (source base) do chính đội phát triển ZK xây dựng. (Đây là nguồn chính thống). Bấm tải về dạng zip, hoặc đơn giản, bạn dán đường link sau vào thanh địa chỉ trình duyệt web để tải về: https://github.com/zkoss/zkessentials/archive/master.zip

Giải nén tập tin zip. Giả sử trên ZK source base được giải nén tại

3. Lập trình với ZK framework

Tìm tập tin main.zul . Ví dụ đường dẫn trên máy tôi là:

Sửa lại nội dung file main.zul . Mục đích: Bạn sẽ thay thế hình ảnh sẵn có bằng 1 label, Chèn thêm 1 nút bấm, khi bấm vào nút này, ZK gọi sự kiện (event), rồi hiện ra một thông báo dạng Message box.

Gọi tiện ích cmd, gõ

để chuyển đến thư mục chứa mã nguồn ZK (Lệnh cd: change directory)

Chờ 1-2 phút để maven tải về toàn bộ dependencies (thư viện) cần thiết, máy chủ (nhúng) Jetty khởi chạy. Mở trình duyệt web, gõ

Gõ vào đường link dài trong web page để gọi ứng dụng:

Done! Bạn không phải là một nhà khoa học tên lửa, nhưng ứng dụng ZK đầu tiên đã hoạt động. It works like a charm!

Việc làm tiếp theo:

4. Tải về và cài đặt ZK studio tại https://www.zkoss.org/product/zkstudio

5. Import project trên vào ZK Studio (ZK studio là phiên bản customize từ Eclipse IDE).

chọn menu File\Import project, chọn Loại import từ existing Maven project bạn nhé.

6. Tra cứu tài liệu Hướng dẫn sử dụng, thực hành theo các ví dụ mẫu
https://www.zkoss.org/zkdemo/grid?zkn=1 để khám phá ZK.

Đỗ Như Vý – Bài viết gốc được đăng tải tại smartjob.vn

Có thể bạn quan tâm:

Xem thêm tuyển dụng CNTT hấp dẫn trên TopDev

Giới thiệu Swagger – Công cụ document cho RESTfull APIs

giới thiệu swagger
Giới thiệu Swagger – Công cụ document cho RESTfull APIs

Bài viết được sự cho phép của tác giả Giang Phan

Trong các bài viết trước, chúng ta đã cùng tìm hiểu cách xây dựng các ứng dụng RESTful API. Một công việc tiếp theo chúng ta cần làm là cung cấp tài liệu hướng dẫn sử dụng API để bên thứ ba có thể sử dụng. Trong bài này, chúng ta sẽ cùng tìm hiểu về Swagger – một công cụ rất mạnh mẽ để tạo một trang quản lý document cho API.

Tìm hiểu về tài liệu hướng dẫn sử dụng API

Tài liệu hướng dẫn sử dụng API là một nội dung kỹ thuật, nó chứa tất cả các thông tin được yêu cầu để có thể làm việc với API, với thông tin chi tiết về các tài nguyên, phương thức, các request và response, thông tin chứng thực, … được hỗ trợ bởi các hướng dẫn và ví dụ.

Tài liệu hướng dẫn sử dụng API thường được tạo và bảo trì bằng các trình soạn thảo văn bản thông thường. Các định dạng mô tả API giống như OpenAPI/Swagger Specification sẽ tự động hóa quá trình xử lý tài liệu, giúp các team dễ dàng hơn trong việc tạo và bảo trì chúng.

  Sử dụng Swagger UI trong jersey REST WS project
  Cài đặt và sử dụng Swagger UI

Xem thêm việc làm SSIS hấp dẫn trên TopDev

Tại sao tài liệu hướng API lại quan trọng?

  • Sản phẩm của chúng ta có thể là tốt nhất, nhưng sẽ không có ai sử dụng nó nếu họ không biết nó làm gì và sử dụng như thế nào.
  • Cải thiện trải nghiệm người dùng: nếu bạn có tài liệu hướng dẫn tốt, nhiều người sẽ dễ dàng tìm thấy giá trị trong các dịch vụ của bạn và sử dụng chúng.
  • Giúp nhiều người biết đến API của bạn: khi có nhiều người chấp nhận và sử dụng các API của chúng ta, họ sẽ giúp chúng ta giới thiệu về các sản phẩm tuyệt vời mà họ đã sử dụng.
  • Tiết kiệm thời gian hỗ trợ và chi phí: tài liệu hướng dẫn tốt, cũng giảm lượng thời gian phải bỏ ra để hỗ trợ những người dùng mới, các thành viên mới của team hoặc đối tác. Tài liệu hướng dẫn tồi hoặc không có, nghĩa là sẽ có nhiều người dùng bực bội vì phải phụ thuộc vào team của bạn để hiểu cách làm việc với API. Ngược lại, khi chúng ta cung cấp cho người dùng khả năng thử nghiệm API trước khi triển khai nó, và cung cấp cho họ tài liệu chi tiết để bắt đầu, bạn sẽ tiết kiệm cho team của mình vô số thời gian trả lời email và các cuộc gọi hỗ trợ.
  • Dễ bảo trì hơn: giúp team của chúng ta biết các chi tiết của tài nguyên, phương thức, các request và response, giúp cho việc bảo trì và cập nhật nhanh hơn.

OpenAPI là gì?

OpenAPI Specification là một định dạng mô tả API dành cho REST APIs. Một file OpenAPI cho phép bạn mô tả toàn bộ API bao gồm:

  • Cho phép những endpoints (/users) và cách thức hoạt động của mỗi endpoint (GET, POST, PUT, DELETE).
  • Các tham số đầu vào & đầu ra của từng API.
  • Phương thức xác thực.
  • Thông tin liên hệ, chứng chỉ (HTTP/ HTTPS), điều khoản sử dụng và những thông tin khác.

API specifications có thể được viết bằng YAML hoặc JSON. Định dạng này dễ đọc, dễ hiểu cho cả người dùng lẫn ngôn ngữ máy tính.

Swagger là gì?

Swagger là một bộ công cụ mã nguồn mở để xây dựng OpenAPI specifications giúp chúng ta có thể thiết kế, xây dựng tài liệu và sử dụng REST APIs.

Swagger cung cấp 3 tools chính cho các developers :

  • Swagger-Editor : dùng để design lên các APIs hoàn toàn mới hoặc edit lại các APIs có sẵn thông qua 1 file config.
  • Swagger-Codegen : dùng để generate ra code từ các file config có sẵn.
  • Swagger-UI : dùng để generate ra file html,css,… từ 1 file config.

Việt viết document cho Swagger có hai cách tiếp cận chính như sau:

  • Top-down approach: thiết kế các API trước khi code.
  • Bottom-up approach: từ các API có sẵn thiết kế file config để mô tả chúng.

Trong các tools trên, Swagger UI được sử dụng nhiều nhất, nó giúp sinh ra giao diện cho tài liệu từ file config dưới chuẩn OpenAPI. Giao diện được hiện ra rõ ràng và tường minh. Dễ dàng đọc hiểu cho cả lập trình viên lẫn người dùng. Sử dụng file config nhưng hoàn toàn tách biệt tác vụ với nhau.

Để dễ hiểu, các bạn có thể truy cập đường link demo với Swagger UI http://petstore.swagger.io/ .

Tại đây ta có thể biết rõ được các thông tin chi tiết về API như: thông tin dự án, các API được cung cấp, method và url tương ứng của nó:

Với mỗi API chúng ta có thể biết được chi tiết input và output cũng như trường nào bắt buộc gửi lên, kết quả trả về có thể nhận những status nào. Đặc biệt, ta có thể input data để thử kiểm tra kết quả.

Cấu trúc cơ bản của Swagger

Chúng ta sẽ xem xét một cấu trúc cở bản của Swagger ở link sau: https://editor.swagger.io

info

Mỗi OpenAPI specifications sẽ bắt đầu với từ khóa openapi để khai báo phiên bản (VD: openapi: 3.0.0). Phiên bản này sẽ định nghĩa toàn bộ cấu trúc của API Phân info sẽ chứa những thông tin của API như: title, desscription (tùy chọn), version.

  • title: tên API.
  • description : thông tin mô tả về API, có thể viết thành nhiều dòng & hỗ trợ cú pháp Markdown.
  • info : thông tin liên hệ, chứng chỉ, điều khoản sử dụng và những thông tin khác.
  • version: phiên bản API.

basePath

Đường dẫn gốc đến thư mục API của project, trong ví dụ này là /v2

tags

Định nghĩa những cái tags, có thể sử dụng để gom những API trong cùng một controllers về một nhóm.

Paths

Đây là phần trọng tâm của API. Ở phần này bạn sẽ định nghĩa những paths trong API của bạn cũng như phương thức, tham số trong API.

  • Path trong API (/user/{userId}).
  • Phương thức của API (GET, POST, DELETE, PUT …).
  • summary là phần mô tả tóm tắt của API.
  • parameters: sẽ là những tham số truyền vào API. Bạn có thể set tham số required hay không, mô tả nó (description) hoặc validate. Đặc biệt trong phần này chúng ta có thể chỉ định 1 schema (Model) để có thể định nghĩa cho phần tham số thông qua schema & $ref.
  • response là phần trả về của server. Chúng ta có thể định nghĩa những HTTP code: 200, 404, 500 … với những mô tả cho từng trường hợp.

Các parameters có khá nhiều khai báo sau từ khóa in mà bạn sẽ phải chú ý đến:

  • in: body : tạo cho người dùng một input-text area mà ở đó người ta có thể nhập data body request vào (sử dụng cho methods PATH/ PUT).
  • in: formData : tạo cho người dùng những input đã định trước mà người ta sẽ nhập data request theo từng field đã định sẵn vào (sử dụng cho methods PATH/ PUT).
  • in: path : tạo cho người dùng một input nhập vào giá trị khai báo trong routes, thường là id.
  • in: query : tạo cho người dùng một input nhập vào giá trị theo các field định sẵn để gửi những query request (sử dụng trong methods GET).
  • in: header : khai báo những giá trị trong header của request mà bạn cần truyền lên.

securityDefinitions

Authentication mà APIs sử dụng để cung cấp tài nguyên.

 

definitions

Định nghĩa các model sử dụng bởi APIs, bao gồm:

  • Tham số đầu tiên là tên của Model (Order).
  • Tiếp đó sẽ là phần kiểu (type) định dạng (object).
  • Sau đó là phần thuộc tính (properties) của Model này.

Cài đặt Swagger UI

Bài viết khá là dài nên chúng ta sẽ tìm hiểu tiếp về cách cài đặt Swagger trong bài viết tiếp theo.

Tài liệu tham khảo:

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm tuyển dụng CNTT hấp dẫn trên TopDev

TOP 100 Công Ty Tốt Nhất Việt Nam Ở Thời Điểm Hiện Tại

top 100 công ty tốt nhất việt nam
TOP 100 Công Ty Tốt Nhất Việt Nam Ở Thời Điểm Hiện Tại

Tìm kiếm một công việc, người lao động không chỉ mong muốn cải thiện thu nhập để chăm lo cho cuộc sống mà còn muốn có cơ hội làm việc trong một môi trường tốt nhất. Bài viết này sẽ tổng hợp Top 100 công ty tốt nhất Việt Nam để người lao động có thể theo dõi và kiếm tìm công việc của mình.

Các công ty có môi trường làm việc tốt nhất được đánh giá theo một số những tiêu chí như chế độ đãi ngộ dành cho nhân viên, lương thưởng, không gian làm việc, số lượng nhân viên, bộ máy tổ chức và quy mô doanh nghiệp.

top 100 công ty tốt nhất việt nam

*Số thứ tự chỉ nhằm liệt kê các công ty, không nhằm mục đích xếp hạng hay đánh giá

1. Tập đoàn Vinamilk – là cái tên luôn xuất hiện trong top những công ty tốt nhất được xếp hạng mỗi năm, thu hút rất nhiều ứng viên tham gia tuyển dụng.

2. Tập đoàn Vingroup – một trong những thương hiệu đang trong đà phát triển năng động nhất Việt Nam.

3. Unilever Việt Nam – công ty đa quốc gia có hoạt động phát triển mạnh tại Việt Nam.

4. Samsung Việt Nam – tập đoàn lớn của Hàn Quốc đã xuất hiện khá sớm tại Việt Nam với lực lượng kỹ sư đông đảo nhất.

5. Công ty cổ phần FPT – công ty công nghệ thuần Việt hàng đầu hiện nay.

Tập đoàn có hệ thống công ty trải khắp Việt Nam, hiện nay FPT cũng đang đẩy mạnh phát triển nhân sự, tuyển dụng các vị trí tại:

6. Tập đoàn viễn thông quân đội Viettel – được đánh giá là nơi có môi trường làm việc trong lĩnh vực công nghệ hấp dẫn số 1 Việt Nam.

Bạn có thể tham khảo các vị trí tuyển dụng của tập đoàn như:

7. Nestle Việt Nam – thương hiệu trực thuộc tập đoàn Unilever Việt Nam

8. P&G Việt Nam – thương hiệu đa quốc gia đến từ Hoa Kỳ.

9. Pesico Việt Nam – chế độ lương thưởng và đãi ngộ được đánh giá cao.

10. Intel Vietnam – công ty công nghệ rất chú trọng trong việc nâng cao năng lực nhân viên.

11. Manulife Việt Nam – công ty hàng đầu ngành bảo hiểm.

12. VinaCapital – đi đầu trong lĩnh vực tài chính.

13. KPMG Vietnam

14. Công ty cổ phần VNG

15. Công ty bảo hiểm nhân thọ Dai-ichi Việt Nam

16. Công Ty Cổ Phần GREENFEED VIỆT NAM

17. Công ty TNHH Nước Giải Khát Coca-Cola Việt Nam

18. Techcombank

Techcombank là một trong những ngân hàng TMCP lớn nhất Việt Nam và một trong những ngân hàng hàng đầu ở Châu Á

19. Công ty TNHH Bảo hiểm Nhân thọ FWD Việt Nam

20. Acecook Việt Nam

21. British American Tobacco Việt Nam

22. PNJ Group

23. Perfetti Van Melle Việt Nam

24. NutiFood

25. Tập đoàn Hưng Thịnh

TẬP ĐOÀN HƯNG THỊNH đã phát triển lớn mạnh với đội ngũ gần 3.000 nhân sự, sở hữu gần 50 Công ty thành viên, 12 văn phòng đại diện cùng hệ thống sàn giao dịch quy mô và để lại dấu ấn đậm nét với gần 80 dự án thuộc nhiều loại hình khác nhau trải dài khắp các tỉnh thành trên cả nước

26. Tập đoàn Bưu chính Viễn thông Việt Nam – VNPT

27. Công ty TNHH LIXIL Việt Nam

28. Maersk Việt Nam

29. Công ty TNHH Brother International (Việt Nam)

30. Công ty Cổ phần Đầu tư Nam Long

31. Công ty TNHH Zuellig Pharma Việt Nam

32. Gamuda Land Việt Nam

33. Lazada Việt Nam

34. Công ty TNHH La Vie

35. Tổ hợp DatVietVAC

36. Chứng khoán Bảo Việt (BVSC)

37. Công ty TNHH Bảo hiểm nhân thọ Generali Việt Nam

38. Daikin Việt Nam

39. Công Ty Cổ Phần Sài Gòn Food

40. Công ty Cổ phần Giải pháp Thanh Toán Việt Nam (VNPAY)

41. Công ty Cổ phần Fecon

42. Công ty Cổ Phần Tập Đoàn Xây Dựng Hòa Bình

43. Công ty Cổ phần Đầu tư Thế Giới Di Động (MWG)

44. Masan Group

45. Mercedes-Benz Vietnam

46. Sony Electronics Việt Nam

47. Mobifone

Một số vị trí tuyển dụng tại Mobifone cho bạn lựa chọn:

  • Trung Tâm Quản Lý, Điều Hành Mạng (NOC) – Chi Nhánh Tổng Công Ty Viễn Thông Mobifone. Xem thêm tại đây
  • Trung Tâm Công nghệ thông tin Mobifone. Xem chi tiết tại đây
  • Trung Tâm Tính Cước và Thanh Khoản MobiFone
  • Mobile Plus, Mobile Services

48. Công ty Honda Việt Nam

49. Ngân Hàng Á Châu

Là một trong những ngân hàng TMCP lớn nhất ở châu Á, chúng tôi đang đầu tư vào đội ngũ nhân sự, thực hành và công nghệ hàng đầu để cải thiện đời sống tài chính của khách hàng. Hãy tham gia cùng 11,000 thành viên của ACB và xây dựng công ty Fintech trong tương lai

Bạn có thể tham khảo các vị trí tuyển dụng IT từ ngân hàng ACB

50. Schneider Electric Việt Nam

51. FrieslandCampina Vietnam

52. AEON Vietnam

53. Novaland Group

54. MBBank

55. Bosch Vietnam

56. Vinasoy

57. GlaxoSmithKline (GSK)

58. Sanofi Vietnam

59. MONDELEZ KINH ĐÔ

60. TP Bank

61. LOTTE Mart

62. Canon Vietnam

63. Bayer Vietnam

64. Roche Vietnam

65. DKSH

66. L’Oréal Vietnam

67. COTECCONS GROUP

68. 3M Việt Nam

69. Pfizer Vietnam Limited

70. FWD Vietnam

71. Biti’s

72. Ernst & Young Vietnam Limited

73. Highlands Coffee

74. Nippon Paint Vietnam

75. Deloitte Việt Nam

76. WIPRO CONSUMER CARE VIỆT NAM

77. TIKI

78. Total Vietnam

79. Đất Xanh Group

80. DHG Pharma

81. ABB LTD.

82. AstraZeneca Vietnam

83. Tập đoàn Thiên Long

84. OPPO Vietnam

85. GreenFeed Vietnam Corporation

86. Sun Group

87. DHL

88. Cargill Vietnam

89. Shopee Việt Nam

90. AB InBev Việt Nam

91. MSD – Merck Sharp & Dohme (Asia) Ltd.

92. CapitaLand Vietnam

93. Novartis Vietnam

94. GRAB

95. Brother Vietnam

96. Công Ty Nhựa Duy Tân

97. INSEE Vietnam

98. Jotun Vietnam

99. Keppel Land Vietnam

100. CMC Corporation

Với top 100 công ty tốt nhất Việt Nam ở thời điểm hiện tại, hi vọng người đọc có thể có thêm thông tin để tìm hiểu và lựa chọn cho mình cơ hội việc làm ở những nơi tốt nhất.


Tuyển Dụng Nhân Tài IT Cùng TopDev
Đăng ký nhận ưu đãi & tư vấn về các giải pháp Tuyển dụng IT & Xây dựng Thương hiệu tuyển dụng ngay!
Hotline: 028.6273.3496 – Email: contact@topdev.vn
Dịch vụ: https://topdev.vn/page/products

Todo List: Liên kết Route và Model tự động trong Laravel

liên kết route và model
Todo List: Liên kết Route và Model tự động trong Laravel

Bài viết được sự cho phép của tác giả Kien Dang Chung

Video trong bài viết

Laravel được lựa chọn để phát triển ứng dụng web vì có rất nhiều các công cụ, tính năng được tích hợp sẵn, nó giúp cho công việc phát triển thuận lợi hơn, viết ít code hơn và code cũng dễ dàng maintain. Route Model Binding là một trong những hạt cát của sa mạc công cụ, nhưng có thể thấy những cái nhỏ nhất cũng chứa đựng đầy tinh thần Laravel.

  Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream
  Cách sử dụng Laravel với Socket.IO

Xem thêm tuyển dụng Laravel lương cao trên TopDev

Route Model Binding là gì?

Trước khi đến với định nghĩa Route Model Binding là gì? chúng ta quay trở lại với các phương thức đã viết code trong TodosController ở những bài trước:

public function show($todoId)
{
    return view('todos.show')->with('todo', Todo::find($todoId));
}

public function edit($todoId)
{
    return view('todos.edit')->with('todo', Todo::find($todoId));
}

public function update($todoId)
{
    $this->validate(request(), [
        'name' => 'required|min:6|max:12',
        'description' => 'required'
    ]);

    $data = request()->all();

    $todo = Todo::find($todoId);
    $todo->name = $data['name'];
    $todo->description = $data['description'];

    $todo->save();
    return redirect('/todos');
}

public function destroy($todoId)
{
    $todo = Todo::find($todoId);
    $todo->delete();
    return redirect('/todos');
}

Để ý kỹ thấy rằng các phương thức này trong TodosController đều có tham số là một biến chứa ID của Todo và trong phương thức đều có một đoạn code thực hiện tìm Todo tương ứng trong database. Nhận ra sự dư thừa này, Laravel đưa ra tính năng Route Model Binding.

Route Model Binding (tạm dịch là Liên kết Route và Model) là một cơ chế truyền một instance của Model trực tiếp vào Route. Ví dụ ở đây thay vì truyền một ID của Todo chúng ta sẽ truyền vào Model Todo. Toàn bộ các phương thức trên có thể viết lại với Route Model Binding như sau:

public function show(Todo $todo)
{
    return view('todos.show')->with('todo', $todo);
}

public function edit(Todo $todo)
{
    return view('todos.edit')->with('todo', $todo);
}

public function update(Todo $todo)
{
    $this->validate(request(), [
        'name' => 'required|min:6|max:12',
        'description' => 'required'
    ]);

    $data = request()->all();

    $todo->name = $data['name'];
    $todo->description = $data['description'];

    $todo->save();
    return redirect('/todos');
}

public function destroy(Todo $todo)
{
    $todo->delete();
    return redirect('/todos');
}

Như vậy, Laravel đã ngầm định rằng phần biến động {todo} trong Route tương ứng với Model Todo khi xử lý trong Controller, rất đơn giản và giảm bớt được việc viết code phải không?

Bạn thử thực hiện lại các chức năng trong ứng dung Todo List, mọi thứ hoạt động bình thường phải không?

Các loại liên kết Route Model

Về phạm vi bài học thì đã kết thúc, xong nhân tiện nói về Liên kết Route Model, chúng ta tìm hiểu thêm một chút. Trong Laravel có hai loại Liên kết Route Model:

Liên kết tự động (Implicit Binding)

Như trong ví dụ trên, Laravel tự động phân giải Model định nghĩa trong Route hoặc trong Controller với các biến đặt tên dạng type-hint. Một chú ý là mặc định Liên kết này sử dụng trường id của Model, nếu bạn muốn sử dụng một trường khác thì khai báo qua phương thức getRouteKeyName() trong Model đó.

Ví dụ: Trong các trang chi tiết của bài viết thì thường người ta sử dụng slug là chuỗi các từ phân cách bởi dấu gạch ngang, chuỗi này sẽ tương ứng với ID bài viết. Ví dụ bạn đang trong bài viết https://allaravel.com/blog/todo-list-lien-ket-route-va-model-tu-dong-trong-laravel thì slug ở đây là todo-list-lien-ket-route-va-model-tu-dong-trong-laravel. Chúng ta khai báo sử dụng slug này như sau trong model Post.

/**
 * Get the route key for the model.
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'slug';
}

Như vậy trong Route chúng ta có thể định nghĩa đường dẫn chi tiết cho bài viết như sau:

Route::get('/blog/{slug}', function(Post $post){
   return view('post.detail')->with('post', $post)
});

Rất hay phải không, chúng ta có thể thực hiện liên kết tự động Route và Model với bất kỳ trường nào có giá trị là duy nhất.

Liên kết theo khai báo (Explicit Binding)

Với kiểu Explicit Binding, chúng ta có thể đưa vào các logic nghiệp vụ riêng. Ở ví dụ trên chúng ta sử dụng slug, nhưng nếu chúng ta vừa muốn sử dụng slug vừa muốn sử dụng id thì thế nào?

Ví dụ, đường dẫn kiểu /blog/bai-viet-thu-nhat và /blog/1 đều có thể hiển thị bài viết đầu tiên. Mặc dù ví dụ này không hữu ích trong thực tế, nhưng sẽ có lúc bạn cần một trường hợp tương tự như vậy. Chúng ta sẽ phải sử dụng đến Explicit Binding, khai báo vào phương thức boot() của RouteServiceProvider:

public function boot()
{
    parent::boot();

    Route::bind('post', function ($value) {
        return App\Post::where('slug', $value)
            ->orWhere('id', $value)
            ->first() ?? abort(404);
    });
}

Bài này hơi dài dòng một tí vì phần này mình thấy khá hay mà trong video ngắn quá, rất mong anh em đóng góp ý kiến giúp All Laravel ngày càng hoàn thiện hơn.

Source code: Bài 15 – Route Model Binding

Bài viết gốc được đăng tải tại allaravel.com

Có thể bạn quan tâm:

Cài đặt và sử dụng Swagger UI

swagger UI

Bài viết được sự cho phép của tác giả Giang Phan

Trong bài trước tôi đã giới thiệu với các bạn một số kiến thức cơ bản về Swagger. Trong bài này, tôi sẽ hướng dẫn các bạn cách cài đặt và sử dụng Swagger UI tool.

Tải thư viện Swagger UI

Các bạn download thư viện Swagger UI từ github repository tại link sau: https://github.com/swagger-api/swagger-ui.

Trong repository trên, bao gồm 3 npm module khác nhau:

  • swagger-ui : là một npm module có thể được sử dụng trong single-page application (SPA), nó tương thích với webpack để quản lý các dependency.
  • swagger-ui-dist : module này bao gồm tất cả mọi thứ cần thiết để sử dụng Swagger UI ở phía server side hoặc SPA mà không cần cài đặt thêm các npm module dependencies.
  • swagger-ui-react : cung cấp các React components được sử dụng cho các React application.
  10+ tools và extensions tuyệt vời cho GraphQL APIs
  3 bước tối ưu hiệu năng React App bằng các API mới của React

Xem thêm tuyển dụng Designer hấp dẫn trên TopDev

Sau khi download xong, bạn tìm đến thư mục swagger-ui/dist mở file index.html sẽ show lên một trang demo tương tự link http://petstore.swagger.io/ như sau:

Như bạn thấy, trong textbox Explore chính là đường linh tới nội dung đặc tả các api.

Deploy Swagger API lên server

Bạn có thể deploy Swagger lên bất kỳ server nào, đơn giản chỉ việc copy tất cả file trong thư mục dist lên server.

Tạo 1 file config để cấu hình API docs của project

Chúng ta sẽ sử dụng editor tool online của Swagger tại link sau https://editor.swagger.io/ để tạo file config cho document API.

Sau đây mình sẽ tạo document cho API với cấu trúc như sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# swagger.yaml
swagger: "2.0"
info:
  description: "Swagger UI demo by gpcoder.com"
  version: "1.0.0"
  title: "Swagger UI Demo"
  termsOfService: "http://swagger.io/terms/"
  contact:
    email: "contact@gpcoder.com"
  license:
    name: "Apache 2.0"
schemes:
  - http
basePath: "/api/v1"
tags:
- name: "Users"
  description: "Everything about user"
paths:
  /users:
    post:
      tags:
      - "Users"
      summary: "Add new user"
      consumes:
      - "application/json"
      - "application/xml"
      produces:
      - "application/json"
      - "application/xml"
      parameters:
      - in: "body"
        name: "data"
        description: "New user info"
        schema:
          type: "object"
          properties:
            name:
              type: "string"
              example: "User 1"
            password:
              type: "string"
              example: "12345678"
      responses:
        200:
          description: "Create user success"
          schema:
            type: "object"
            properties:
              name:
                type: "string"
                example: "User 1"
        405:
          description: "Invalid input"

Các key trong file config mình đã mô tả rõ ở bài viết trước, các bạn có thể xem lại tại link sau: https://gpcoder.com/5967-gioi-thieu-swagger-cong-cu-document-cho-restfull-apis/

Lưu nội dung file trên với tên swagger.yaml tại thư mục swagger-ui/dist.

  • Trên menu File của https://editor.swagger.io/ -> chọn Save as YAML hoặc chọn Convert and save as JSON.

Trỏ URL đến file config

Để sử dụng swagger, trong file dist/index.html cần phải trỏ URL đến file swagger đã tạo ở trên.

Tìm đến đoạn js cuối file, và đổi url: “http://petstore.swagger.io/v2/swagger.json” thành URL trỏ tới file swagger.yaml đã tạo ở trên.

Giả sử chúng ta đã deploy swagger lên server ở địa chỉ http://localhost:8012/swagger-ui/ và file swagger.yaml chúng ta đặt cùng thư mục với file index.html. Chúng ta sẽ sửa lại nội URL trên như sau:

http://localhost:8012/swagger-ui/swagger.yaml

Chúng ta có kết quả như sau:

Swagger hỗ trợ cả YAML và JSON. Các bạn có thể thử đổi URL đến JSON để kiểm tra kết quả.

Viết file swagger config hiệu quả với $ref

Chúng ta có thể tiếp tục thêm tất cả các API vào paths trong file swagger.yaml để hoàn thành document API cho project của mình.

Tuy nhiên có một vấn đề phát sinh là khi project càng phình to, càng nhiều API thì file swagger.yaml của lớn. Khi cần thêm mới hay chỉnh sửa sẽ rất khó khăn.

Để giải quyết vấn đề này chúng ta sẽ chia nhỏ file swagger.yaml ra thành nhiều file và sử dụng $ref trong swagger.yaml để trỏ tới những file mà ta vừa tách ra.

Giả sử chúng ta tái cấu trúc thư mục của mình như sau:

|__swagger-ui/
|__swagger.yaml

Bây giờ, mình sẽ tách file swagger.yaml ở trên ra theo cấu trúc thư mục như sau:

|__swagger-ui/
|__swagger.yaml
|__components/
|____users.yaml

Nội dung các file config bây giờ đổi lại như sau:

swagger.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# swagger.yaml
swagger: "2.0"
info:
  description: "Swagger UI demo by gpcoder.com"
  version: "1.0.0"
  title: "Swagger UI Demo"
  termsOfService: "http://swagger.io/terms/"
  contact:
    email: "contact@gpcoder.com"
  license:
    name: "Apache 2.0"
schemes:
  - http
basePath: "/api/v1"
tags:
- name: "Users"
  description: "Everything about user"
paths:
  /users:
    $ref: components/users.yaml

components/users.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# components/users.yaml
post:
  tags:
  - "Users"
  summary: "Add new user"
  consumes:
  - "application/json"
  - "application/xml"
  produces:
  - "application/json"
  - "application/xml"
  parameters:
  - in: "body"
    name: "data"
    description: "New user info"
    schema:
      type: "object"
      properties:
        name:
          type: "string"
          example: "User 1"
        password:
          type: "string"
          example: "12345678"
  responses:
    200:
      description: "Create user success"
      schema:
        type: "object"
        properties:
          name:
            type: "string"
            example: "User 1"
    405:
      description: "Invalid input"

Như bạn thấy, nội dung file config của chúng ta đơn giản hơn rất nhiều. Chúng ta có thể dễ dàng thay đổi  hay thêm mới document cho API.

Trên đây là hướng dẫn cơ bản về cài đặt và sử dụng Swagger UI tool. Trong bài viết tiếp theo, chúng ta sẽ thực hiện tạo nội dung đặc tả cho api từ code có sẵn để hiện lên Swagger UI.

Tài liệu tham khảo:

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm công việc CNTT hấp dẫn trên TopDev

Sử dụng Swagger UI trong jersey REST WS project

swagger ui
Sử dụng Swagger UI trong jersey REST WS project

Bài viết được sự cho phép của tác giả Giang Phan

Trong các bài viết trước, tôi đã giới thiệu với các bạn Swagger và cách cài đặt, sử dụng Swagger UI. Trong thực tế, các API thường được thay đổi bởi các developer và họ ít khi mở Swagger editor để cập nhật lại các document hoặc vì lý do nào đó mà họ không cập nhật document mới nhất theo source code. Một vấn đề đặt ra là có cách nào để API document có thể cập nhật một cách tự động mỗi khi code thay đổi và đặt cùng một nơi trong code để developer dễ dàng cập nhật hay không? Câu trả là là có và tôi sẽ hướng dẫn các bạn thực hiện trong phần tiếp theo của bài viết này.

  SWAP-No ROOT: Cách tạo Ram ảo cho Android không cần Root
  Các kĩ sư Pinterest đã xây dựng Progressive Web App như thế nào?

Xem thêm việc làm Linux lương cao trên TopDev

Tích hợp JAX-RS REST project với Swagger UI để tạo API document một cách tự động

Tiếp tục bài viết về xây dựng RESTful API với Jersey, trong bài này tôi sẽ hướng dẫn các bạn cách tích hợp JAX-RS REST project với Swagger UI để tạo API document một cách tự động. Nếu các bạn làm Spring project có thể tìm hiểu về Springfox – đây là một thư viện rất mạnh mẽ và dễ sử dụng để tạo REST API document. Tôi sẽ hướng dẫn các bạn Springfox ở series bài viết về Spring Framework.

Ý tưởng:

  • Tạo REST API sử dụng Jersey 2.
  • Sử dụng Swagger Annotation để mô tả thông tin về resource.
  • Sử dụng Swagger core để sinh file đặc tả Swagger API theo chuẩn OpenAPI 3, output có thể là json hoặc yaml.
  • Sử dụng thư viện Swagger UI để sinh ra giao diện cho document từ file config dưới chuẩn OpenAPI.

Để mọi thứ có thể thực hiện một cách tự động, chúng ta sẽ sử dụng Maven – một chương trình quản lý dự án cho phép các developers có thể quản lý về version, các dependencies (các component, thư viện sử dụng trong dự án) , quản lý build, tự động download javadoc & source, ….

Các maven plugin cần thiết để tích hợp Jersey với Swagger UI:

  • maven-dependency-plugin : plugin này giúp donwload các static Swagger UI file được đóng gói trong webjar từ Maven dependency.
  • maven-war-plugin : plugin này giúp copy các static Swagger UI file vào thư mục swagger-ui trong war file của project.
  • replacer : được sử dụng để thay thế URL đến file OpenAPI specification trong file index.html của Swaggers UI.

Ví dụ

Tôi sẽ sử dụng lại ví dụ ở bài viết “JWT – Token-based Authentication trong Jersey 2.x” để hướng dẫn các bạn cách tạo document tự động cho các API này.

Các bước thực hiện:

  • Tạo maven project và khai báo các thư viện, plugin cần thiết.
  • Cấu hình Jersey.
  • Thêm cấu hình API trong file web.xml.
  • Tạo file đặc tả API cho project: openapi.yaml.
  • Sử dụng các Swagger Annotation để mô tả API.
  • Build project và sử dụng.

Tạo maven project và khai báo các thư viện, plugin cần thiết

Tạo maven project với cấu trúc như sau:

Mở file pom.xml và thêm các dependency sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>SwaggerWithJersey2Example</groupId>
    <artifactId>SwaggerWithJersey2Example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <jersey.version>2.28</jersey.version>
        <lombok.version>1.16.20</lombok.version>
        <javax.servlet-api.version>4.0.1</javax.servlet-api.version>
        <javax.ws.rs-api.version>2.1.1</javax.ws.rs-api.version>
        <swagger.version>2.0.8</swagger.version>
        <swagger-ui.version>3.23.4</swagger-ui.version>
        <replacer.version>1.5.3</replacer.version>
    </properties>
    <dependencies>
        <!-- Javax -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${javax.servlet-api.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>${javax.ws.rs-api.version}</version>
        </dependency>
        <!-- Jersey -->
        <dependency>
            <groupId>org.glassfish.jersey.connectors</groupId>
            <artifactId>jersey-apache-connector</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-server -->
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-client -->
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-common -->
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-common</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson -->
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-multipart -->
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-multipart</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- Java JWT: JSON Web Token for Java -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.10.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.10.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.10.5</version>
            <scope>runtime</scope>
        </dependency>
        <!-- Uncomment this next dependency if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms: -->
        <!-- <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.60</version>
            <scope>runtime</scope>
        </dependency> -->
        <!-- Swagger -->
        <!-- https://mvnrepository.com/artifact/io.swagger.core.v3/swagger-jaxrs2 -->
        <dependency>
            <groupId>io.swagger.core.v3</groupId>
            <artifactId>swagger-jaxrs2</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.swagger.core.v3/swagger-jaxrs2-servlet-initializer -->
        <dependency>
            <groupId>io.swagger.core.v3</groupId>
            <artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
            <version>${swagger.version}</version>
        </dependency>
    </dependencies>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <!-- Build with specified Java version -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <!-- Download Swagger UI webjar -->
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.1.1</version>
                <executions>
                    <execution>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <!-- https://mvnrepository.com/artifact/org.webjars/swagger-ui -->
                                <dependency>
                                    <groupId>org.webjars</groupId>
                                    <artifactId>swagger-ui</artifactId>
                                    <version>${swagger-ui.version}</version>
                                </dependency>
                            </artifactItems>
                            <outputDirectory>${project.build.directory}/swagger-ui</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <!-- Add Swagger UI resources to the war file. -->
                <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-war-plugin -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.3</version>
                <configuration>
                    <webResources combine.children="append">
                        <resource>
                            <directory>${project.build.directory}/swagger-ui/META-INF/resources/webjars/swagger-ui/${swagger-ui.version}</directory>
                            <includes>
                                <include>**/*.*</include>
                            </includes>
                            <targetPath>swagger-ui</targetPath>
                        </resource>
                    </webResources>
                </configuration>
            </plugin>
            <plugin>
                <!-- Replace the OpenAPI specification example URL with the local one. -->
                <!-- https://mvnrepository.com/artifact/com.google.code.maven-replacer-plugin/replacer -->
                <groupId>com.google.code.maven-replacer-plugin</groupId>
                <artifactId>replacer</artifactId>
                <version>${replacer.version}</version>
                <executions>
                    <execution>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>replace</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <file>${project.build.directory}/swagger-ui/META-INF/resources/webjars/swagger-ui/${swagger-ui.version}/index.html</file>
                    <replacements>
                        <replacement>
                            <token>https://petstore.swagger.io/v2/swagger.json</token>
                            <value>/api/openapi.json</value>
                        </replacement>
                    </replacements>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Các bạn nhớ update maven project để download tất cả thư viện về máy nhé.

Cấu hình Jersey

Mở file com.gpcoder.config.JerseyServletContainerConfig thêm khai báo package swagger: io.swagger.v3.jaxrs2.integration.resources.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.gpcoder.config;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.logging.LoggingFeature;
//Deployment of a JAX-RS application using @ApplicationPath with Servlet 3.0
//Descriptor-less deployment
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
public class JerseyServletContainerConfig extends ResourceConfig {
    public JerseyServletContainerConfig() {
        // if there are more than two packages then separate them with semicolon
        packages("io.swagger.v3.jaxrs2.integration.resources,com.gpcoder");
        register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), Level.INFO,
                LoggingFeature.Verbosity.PAYLOAD_ANY, 10000));
        register(JacksonFeature.class);
        
        // This authorization feature is not automatically turned on.
        // We need to turn it on by ourself.
        register(RolesAllowedDynamicFeature.class);
    }
}

Thêm cấu hình API trong file web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
    <display-name>Swagger with Jersey2 Example by gpcoder</display-name>
    <servlet>
        <servlet-name>api</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.gpcoder.config.JerseyServletContainerConfig</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>api</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>

Tạo file đặc tả API cho project: openapi.yaml

Khai báo một số thông tin cơ bản về API và security theo OpenAPI Specification.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
prettyPrint: true
cacheTTL: 0
openAPI:
  info:
    description: "Swagger UI demo by gpcoder.com"
    version: "1.0.0"
    title: "Swagger UI Demo"
    termsOfService: "http://swagger.io/terms/"
    contact:
      email: "contact@gpcoder.com"
    license:
      name: "Apache 2.0"
      url: "http://www.apache.org/licenses/LICENSE-2.0.html"
  servers:
    - url: '/api'
  # 1) Define the security scheme type (HTTP bearer)
  components:
    securitySchemes:
      bearerAuth:            # arbitrary name for the security scheme
        type: http
        scheme: bearer
        bearerFormat: JWT    # optional, arbitrary value for documentation purposes
  # 2) Apply the security globally to all operations
  security:
    - bearerAuth: []         # use the same name as above

Trong project này, chúng ta cần chứng thực user sử dụng JWT, nên cần khai báo một số thông tin về security. Chi tiết về Security OpenAPI Specification, các bạn tham khảo thêm ở link sau: https://swagger.io/docs/specification/authentication/bearer-authentication/

Sử dụng các Swagger Annotation để mô tả API

Bây giờ chúng ta sử dụng các Swagger Annotation được cung cấp bởi Swagger core để mô tả các API.

Chi tiết tất cả các Swagger Annotation, các bạn tham khảo tại đây: https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X—Annotations

AuthService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.gpcoder.api;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.gpcoder.helper.JwTokenHelper;
import com.gpcoder.model.User;
import com.gpcoder.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
@Path("/auth")
@Tag(name = "Authentication services",
    description = "Authenticating a user and issuing a JSON Web Token (JWT)")
public class AuthService {
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Operation(summary = "Authenticating a user",
        description = "Authenticating a user with their username/ password and issuing a JSON Web Token (JWT)",
        responses = {
                 @ApiResponse(description = "Authenticated user based on the given information",
                         content = @Content(mediaType = "application/json",
                         schema = @Schema(implementation = String.class))),
                 @ApiResponse(responseCode = "200", description = "success"),
                 @ApiResponse(responseCode = "403", description = "Wrong username or password."),
                 @ApiResponse(responseCode = "500", description = "Internal Server Error.")
             })
    public Response authenticateUser(
            @Parameter(description = "The user name for login. Some test account: admin, customer, gpcoder", required = true)
            @FormParam("username") String username,
            @Parameter(description = "The password for login", required = true)
            @FormParam("password") String password) {
        // Authenticate the user using the credentials provided
        UserService userService = new UserService();
        User user = userService.getUser(username);
        if (user == null || !user.getPassword().equals(password)) {
            return Response.status(Response.Status.FORBIDDEN) // 403 Forbidden
                    .entity("Wrong username or password") // the response entity
                    .build();
        }
        // Issue a token for the user
        String token = JwTokenHelper.createJWT(user);
        // Return the token on the response
        return Response.ok(token).build();
    }
}

OrderService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.gpcoder.api;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import com.gpcoder.model.Order;
import com.gpcoder.model.Role;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
// URI:
// http(s)://<domain>:(port)/<YourApplicationName>/<UrlPattern in web.xml>/<path>
// http://localhost:8080/api/orders
@Path("/orders")
@PermitAll
@Consumes(value = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN })
@Produces(value = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN })
@Tag(name = "Order service",
    description = "CRUD operations for order service. User must be authorized with some resources.")
public class OrderService {
    @GET
    @Path("/{id}")
    @Operation(summary = "Get order by id", description = "This action published for everyone")
    @ApiResponse(responseCode = "200", description = "Get order by id")
    public Response get(@PathParam("id") int id) {
        System.out.println("OrderService->get()");
        return Response.ok("OrderService->get()").build();
    }
    @Operation(
        summary = "Insert an order",
        responses = {
             @ApiResponse(description = "Inserted an order based on the given information",
                     content = @Content(mediaType = "application/json",
                     schema = @Schema(implementation = String.class))),
             @ApiResponse(responseCode = "200", description = "success"),
             @ApiResponse(responseCode = "401", description = "User cannot access this resource."),
             @ApiResponse(responseCode = "403", description = "User not authorized."),
             @ApiResponse(responseCode = "500", description = "Internal Server Error.")
         })
    @POST
    @RolesAllowed(Role.ROLE_CUSTOMER)
    public Response insert(Order order, @Context SecurityContext securityContext) {
        System.out.println("User: " + securityContext.getUserPrincipal().getName());
        System.out.println("OrderService->insert()");
        return Response.ok("OrderService->insert()").build();
    }
    @PUT
    @RolesAllowed({ Role.ROLE_ADMIN, Role.ROLE_CUSTOMER })
    @Operation(summary = "Update order", description = "Admin and Customer can do this action")
    public Response update(Order order) {
        System.out.println("OrderService->update()");
        return Response.ok("OrderService->update()").build();
    }
    @DELETE
    @Path("/{id}")
    @RolesAllowed(Role.ROLE_ADMIN)
    @Operation(summary = "Delete order by id", description = "Only Admin can do this action")
    public Response delete(@PathParam("id") int id) {
        System.out.println("OrderService->delete()");
        return Response.ok("OrderService->delete()").build();
    }
}

Build project và sử dụng

Các bạn chọn chuột phải lên project -> Run As -> Maven install. Sau khi chạy xong bạn sẽ thấy các thư viện Swagger UI đã được tải về và giải nén trong thư mục target của project như sau:

Mở file index.html trong thư mục target/swagger-ui/META-INF/resources/webjars/swagger-ui/${swagger-ui.version} , bạn sẽ thấy đường dẫn đến file mô tả swagger.json đã được thay thế bằng /api/openapi.json như đã config trong file pom.xml.

Mọi thứ đã xong, bây giờ các bạn có thể start server lên để kiểm tra kết quả.

  • Kiểm tra file openapi.json tồn tại và chứa tất cả các đặc tả về API document. Truy cập vào địa chỉ: http://localhost:8080/api/openapi.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
{
  "openapi" : "3.0.1",
  "info" : {
    "title" : "Swagger UI Demo",
    "description" : "Swagger UI demo by gpcoder.com",
    "termsOfService" : "http://swagger.io/terms/",
    "contact" : {
      "email" : "contact@gpcoder.com"
    },
    "license" : {
      "name" : "Apache 2.0",
      "url" : "http://www.apache.org/licenses/LICENSE-2.0.html"
    },
    "version" : "1.0.0"
  },
  "servers" : [ {
    "url" : "/api"
  } ],
  "security" : [ {
    "bearerAuth" : [ ]
  } ],
  "tags" : [ {
    "name" : "Authentication services",
    "description" : "Authenticating a user and issuing a JSON Web Token (JWT)"
  }, {
    "name" : "Order service",
    "description" : "CRUD operations for order service. User must be authorized with some resources."
  } ],
  "paths" : {
    "/auth" : {
      "post" : {
        "tags" : [ "Authentication services" ],
        "summary" : "Authenticating a user",
        "description" : "Authenticating a user with their username/ password and issuing a JSON Web Token (JWT)",
        "operationId" : "authenticateUser",
        "requestBody" : {
          "content" : {
            "application/x-www-form-urlencoded" : {
              "schema" : {
                "type" : "object",
                "properties" : {
                  "username" : {
                    "type" : "string"
                  },
                  "password" : {
                    "type" : "string"
                  }
                }
              }
            }
          }
        },
        "responses" : {
          "default" : {
            "description" : "Authenticated user based on the given information",
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "200" : {
            "description" : "success"
          },
          "403" : {
            "description" : "Wrong username or password."
          },
          "500" : {
            "description" : "Internal Server Error."
          }
        }
      }
    },
    "/orders/{id}" : {
      "get" : {
        "tags" : [ "Order service" ],
        "summary" : "Get order by id",
        "description" : "This action published for everyone",
        "operationId" : "get",
        "parameters" : [ {
          "name" : "id",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "Get order by id"
          }
        }
      },
      "delete" : {
        "tags" : [ "Order service" ],
        "summary" : "Delete order by id",
        "description" : "Only Admin can do this action",
        "operationId" : "delete",
        "parameters" : [ {
          "name" : "id",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "default" : {
            "description" : "default response",
            "content" : {
              "application/json" : { },
              "application/xml" : { },
              "text/plain" : { }
            }
          }
        }
      }
    },
    "/orders" : {
      "put" : {
        "tags" : [ "Order service" ],
        "summary" : "Update order",
        "description" : "Admin and Customer can do this action",
        "operationId" : "update",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            },
            "application/xml" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            },
            "text/plain" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            }
          }
        },
        "responses" : {
          "default" : {
            "description" : "default response",
            "content" : {
              "application/json" : { },
              "application/xml" : { },
              "text/plain" : { }
            }
          }
        }
      },
      "post" : {
        "tags" : [ "Order service" ],
        "summary" : "Insert an order",
        "operationId" : "insert",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            },
            "application/xml" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            },
            "text/plain" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            }
          }
        },
        "responses" : {
          "default" : {
            "description" : "Inserted an order based on the given information",
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "200" : {
            "description" : "success"
          },
          "401" : {
            "description" : "User cannot access this resource."
          },
          "403" : {
            "description" : "User not authorized."
          },
          "500" : {
            "description" : "Internal Server Error."
          }
        }
      }
    }
  },
  "components" : {
    "schemas" : {
      "Order" : {
        "type" : "object",
        "properties" : {
          "id" : {
            "type" : "integer",
            "format" : "int32"
          },
          "name" : {
            "type" : "string"
          }
        }
      }
    },
    "securitySchemes" : {
      "bearerAuth" : {
        "type" : "http",
        "scheme" : "bearer",
        "bearerFormat" : "JWT"
      }
    }
  }
}
  • Kiểm tra Swagger UI đã hiển thị đầy đủ các API document như đã config trong file WebContent/WEB-INF/openapi.yaml và đúng như mô tả trong Swagger Annotation. Truy cập địa chỉ: http://localhost:8080/swagger-ui/index.html

Các bạn có thể chạy thử POST /auth để lấy jwt token và chọn Authorize để config token cho các request đến API cần chứng thực.

Tiếp tục, chúng ta sẽ kiểm tra thông tin đã mô tả trong phương thức OrderService#insert.

Như các bạn có thể thấy, Swagger có thể generate ra 1 file config (.json hoặc .yaml) từ chính code của chương trình. Tuy nhiên phần UI của swagger lại khá rườm rà không đẹp lắm. Để có một beautiful document cho các API, các bạn có thể tìm hiểu thêm về Slate – một công cụ open source giúp generate ra các file html, css,… từ 1 file config .md . Slate có UI cực kì đẹp và khoa học.

Slate rất đẹp nhưng lại không thể generate ra file config như swagger. Vì vậy để tận dụng thế mạnh của Swagger và Slate, chúng ta cần phải convert 1 file config.yaml của Swagger sang 1 file config.md. Sau đó dùng Slate để generate ra các file html, css,… để publish ra bên ngoài. Chi tiết các bạn có thể tham khảo thêm tại link sau: https://github.com/lord/slate.

 

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm tuyển dụng IT hấp dẫn trên TopDev

Data types trong RAML

data types
Data types trong RAML

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

Khi khai báo các request parameter, path parameter, request body, response body, … trong RAML, chúng ta cần khai báo kiểu dữ liệu của những thông tin này. RAML định nghĩa nhiều loại data types khác nhau giúp chúng ta có thể giải quyết những nhu cầu của mình. Trong bài viết này, chúng ta sẽ cùng tìm hiểu về data types trong RAML như thế nào, các bạn nhé!

  Cách cài đặt .NET Framework 3.5 trên Windows thành công 100%
  Định nghĩa request body và response với RAML

Xem thêm nhiều việc làm IOT Engineering hấp dẫn trên TopDev

Đầu tiên, các bạn hãy nhìn vào hình dưới, tổng quan thì RAML định nghĩa những loại data types được phân cấp như sau:

Như các bạn thấy, ở top của diagram trên, chúng ta có data type là any. Thông tin được định nghĩa với type any sẽ không có hạn chế gì cả, các bạn có thể định nghĩa số, chữ, đối tượng, bất cứ kiểu dữ liệu gì mà các bạn muốn.

Bên dưới data type any, chúng ta có các data type chi tiết, cụ thể hơn, hạn chế hơn nếu thông tin được định nghĩa bởi những data type này. Như các bạn thấy, chúng ta có các scalar types, array, object, union, XSD schema và cả JSON schema.

Nói nôm na scalar types là những kiểu dữ liệu đơn giản, không được định nghĩa từ những kiểu dữ liệu khác, ví dụ như boolean, string, null, file,… Giá trị của những thông tin được định nghĩa với những scalar types này là single, boolean thì chỉ có true, false; string thì giá trị chỉ là các chuỗi…

Kiểu dữ liệu array thì giúp chúng ta định nghĩa mảng dữ liệu, có thể là mảng string, mảng number hoặc thậm chí là mảng các đối tượng, giống như trong Java đó các bạn!

Object thì giúp chúng ta định nghĩa thông tin về đối tượng, với nhiều properties thuộc về đối tượng này.

Union là kiểu dữ liệu giúp chúng ta có thể định nghĩa giá trị sử dụng nhiều loại data types khác nhau.

XSD và JSON schema thì giúp chúng ta định nghĩa thông tin sử dụng schema của XML và JSON.

Bài viết gốc được đăng tải tại huongdanjava.com

Có thể bạn quan tâm:

Embedded Là Gì? Triển Vọng Công Việc Nào Từ Lĩnh Vực Embedded Cho Ngành IT Việt Nam Hiện Tại?

embedded là gì
Embedded Là Gì? Triển Vọng Công Việc Nào Từ Lĩnh Vực Embedded Cho Ngành IT Việt Nam Hiện Tại?

Sự phát triển của IoT trở nên mạnh mẽ hơn bao giờ hết cũng đồng thời mở ra cơ hội cho sự lớn mạnh của Embedded. Với những cá nhân đang hoạt động trong lĩnh vực công nghệ thông tin, đây không còn là thuật ngữ quá xa lạ, nhưng với người ngoài ngành, đây vẫn là khái niệm còn mới lạ. Vậy Embedded là gì? Triển vọng nghề nghiệp nào cho bạn nếu quyết định theo đuổi vị trí Embedded Developer?

embedded là gì
Sự phát triển của Embedded trong cuộc sống hiện đại

Tìm hiểu về thuật ngữ Embedded là gì

1. Embedded System là gì?

Embedded System còn được biết đến với cái tên thuần Việt là Hệ thống nhúng. Đây là một phần mềm được viết dựa trên sự kết hợp giữa phần cứng và phần mềm của máy tính, với một chức năng chung hoặc một chức năng cụ thể cho hệ thống máy chủ. Khác với phần mềm dành cho web hay mobile, embedded system tương tác với thế giới thật trong một khoảng thời gian thật. Rất nhiều các thiết bị như thiết bị chế biến, y tế, ô tô, đồ gia dụng, các thiết bị di động,… đều cần đến sự ứng dụng của Embedded System.

  Cơ bản về Embedded và ứng dụng
  .NET – Strong Named Assembly là gì?

2. Một số đặc điểm chính của Embedded System

  • Một Embedded system sẽ gồm có phần cứng (hardware), phần mềm (software) và phần sụn (firmware). Do đó sẽ có sự khác biệt về độ phức tạp, chức năng cũng như ảnh hưởng đến các phần này khi sử dụng.
  • Chúng thường được sử dụng cho cảm biến và tính toán thời gian thực trên IoT, thông qua việc kết nối internet mà không yêu cầu cần có sự hoạt động của người dùng.
  • Hoạt động dựa trên bộ vi điều khiển hoặc bộ vi xử lý, đều là các mạch tích hợp cung cấp năng lượng tính toán cho hệ thống.
  • Chúng thường được nhúng trong một hệ thống chung, lớn hơn để thực hiện một chức năng cụ thể, chuyên biệt trong hệ thống chứ không phải là thực hiện các nhiệm vụ khác nhau.

Xem embedded tuyển dụng đãi ngộ tốt trên TopDev

3. Embedded Software là gì?

Xoay quanh embedded không thể không nhắc đến khái niệm Embedded Software. Tương tự như hệ thống nhúng, Embedded Software là một phần mềm cụ thể sẽ được ghi vào bộ nhớ của thiết bị để có thể phục vụ cho mục đích ROM một cách dễ dàng hơn. Firmware được lưu trữ trong các bộ nhớ cố định, trong đó, ROM có thể lập trình và PROM có thể xóa hoặc bộ nhớ Flash.

embedded software

Embedded được ứng dụng như thế nào trong cuộc sống?

Hiện nay hệ thống Embedded đã được ứng dụng rất nhiều trong cuộc sống mà bạn có thể bắt gặp ở bất cứ đâu.

  • Thành phố thông minh (Smart City): Rất nhiều các quốc gia trên thế giới đã ứng dụng các thiết bị điện tử và hệ thống IoT trong việc quản lý mạng lưới thông tin của thành phố. Mạng lưới sinh thái thông minh này sẽ giúp chính quyền dễ dàng hơn trong việc quản lý quy trình nhập cư, tình hình an ninh, giao thông, y tế, giáo dục,… và rất nhiều các dịch vụ cộng đồng khác.
  • Nhà cửa thông minh (Smarthome): Không khó để bắt gặp hầu hết các vật dụng trong ngôi nhà của bạn hiện tại đều ít nhiều có sự góp mặt của Embedded Software. Từ các thiết bị điện tử, điện thoại thông minh, điều hòa không khí, TV, tủ lạnh, máy ảnh, robot hút bụi cho đến máy pha cà phê,… đều có sự hiện diện của phần mềm embedded. Chủ nhà sẽ quản lý các thiết bị này thông qua internet và các đường truyền kết nối không dây. Mục đích của công nghệ này là để tiết kiệm tối đa công sức và thời gian mà con người bỏ ra cho các hoạt động nội trợ hằng ngày.

ứng dụng của embedded

  • Công nghiệp ô tô: Công nghệ hiện đại đã cho phép sản xuất một chiếc xe ô tô với sự can thiệp xuyên suốt của hệ thống embedded. Từ hệ thống hộp số tự động, máy kiểm soát hành trình, hệ thống chống cứng bó phanh hay các cảm biến được thiết kế để giúp xe di chuyển an toàn, giảm thiểu các rủi ro,… Tất cả đều nhờ có sự xuất hiện của phần mềm embedded.
  • Không gian vũ trụ và lĩnh vực quân sự: Để đảm bảo an toàn ở mức cao nhất cho con người trong quá trình chinh phục không gian, việc sử dụng các giải pháp embedded thật sự cần thiết. Hệ thống embedded có thể được ứng dụng trong việc chế tạo các cảm biến hiệu suất cao, các giải pháp để điều hướng và liên lạc trong không gian và trong quân sự. Các tín hiệu được gửi đi giữa hai bên giúp cho việc điều khiển vệ tinh hay khi chiến đấu diễn ra suôn sẻ hơn.

Xem thêm Những Thông Tin Cần Biết Về Vị Trí ICT Business Analyst

Cơ hội công việc nào cho các Embedded Developer ở thời điểm hiện tại

Kết quả thống kê của BBC Research Group cho thấy, từ cách đây hơn 10 năm, tổng doanh thu của thị trường Embedded System và các công việc liên quan đến Embedded Software đã hơn 88 tỷ USD. Ở Việt Nam hiện tại, sự phát triển của các công việc liên quan đến embedded vẫn chưa thật sự bùng nổ so với thế giới. Tuy nhiên, trong thời điểm số hóa toàn cầu như hiện nay, công việc này chắc chắn sẽ được săn đón nhiều hơn trong tương lai.

Tham khảo tuyển dụng embedded Hà Nội lương cao trên TopDev

Các công việc có chuyên môn liên quan đến Blockchain, Fullstack hay Embedded Software trong tương lai sẽ tiếp tục được nhiều công ty chú ý đến. Để có thể tìm được cho mình một công việc ưng ý, bạn hãy chú trọng trong việc nâng cấp chuyên môn và kỹ năng chuyên ngành cho mình. Đó chính là con đường để bạn đón đầu xu hướng công việc trong tương lai và có cho mình mức thu nhập tốt nhất.

Có thể hiểu một cách đơn giản rằng thế giới thông minh mà bạn đã được sống hiện tại chính là kết quả nổi bật nhất của Embedded System. Embedded gắn liền với sự thông minh, do đó trong kỷ nguyên trí tuệ nhân tạo như hiện tại, các Embedded developers đang có cơ hội rộng mở hơn bao giờ hết.

Có thể bạn quan tâm:

Truy cập ngay việc làm IT đãi ngộ tốt trên TopDev