Home Blog Page 74

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

Chia sẻ 6 cách sửa lỗi bàn phím máy tính bị lag, phản hồi chậm

sửa lỗi bàn phím
Chia sẻ 6 cách sửa lỗi bàn phím máy tính bị lag, phản hồi chậm

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

Bạn đã bao giờ cảm thấy khó chịu với bàn phím mà bạn đang gõ chưa, nhất là đối với bàn phím rời (kết nối với máy tính thông qua Bluetooh) thì hay có hiện tượng giật, lag và delay nhẹ. Tức là bạn gõ được một lúc rồi thì chữ mới hiện ra ấy.

Tuy nhiên, trước khi đến với những cách khắc phục bên dưới thì bạn cần phải đảm bảo rằng nguyên nhân không phải đến từ những lỗi khác. Bởi đôi khi máy tính của bạn bị chậm cũng là nguyên nhân khiến bàn phím của bạn bị delay.

Vậy nên, hãy thử khởi động lại máy tính và kiểm tra lại bàn phím một lần nữa xem sao, hoặc nếu có sẵn một cái bàn phím khác thì có thể kết nối thử xem có bị hiện tượng tương tự như vậy không.

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

#1. Tắt tính năng Filter Keys

Filter Keys có cách hoạt động tương tự Sticky Keys. Nói một cách dễ hiểu thì Filter Keys là khả năng tiếp cận giúp bạn điều chỉnh phản hồi của bàn phím khi thao tác tổ hợp phím lặp lại đi lặp lại sẽ được bỏ qua. Đây có thể là nguyên nhân gây ra độ trễ cho bàn phím. Bạn có thể tắt Filter Keys bằng cách sau:

+ Bước 1: Mở Windows Settings lên bằng cách nhấn tổ hợp phím Win + I.

cach-giam-do-tre-ban-phim-tren-windows (1)

+ Bước 2: Bạn tìm đến tính năng Ease of Access => và bấm chọn tính năng này.

cach-giam-do-tre-ban-phim-tren-windows (2)

+ Bước 3: Bạn vào tab Keyboard => sau đó ở tùy chọn Use Filter Keys, bạn chọn OFF.

cach-giam-do-tre-ban-phim-tren-windows (3)

#2. Thay đổi thuộc tính bàn phím

Vâng, thay đổi thuộc tính bàn phím cũng là một cách để giúp bạn giải quyết vấn đề bị delay khi gõ phím.

+ Bước 1: Bạn nhấn tổ hợp phím Win + R để mở hộp thoại Run => sau đó nhập lệnh control keyboard => và bấm Enter để mở Keyboard Properties.

cach-giam-do-tre-ban-phim-tren-windows (8)

+ Bước 2: Ở khu vực Character repeart có hai thanh trượt là Repeart delay và Repeart rate. Bạn hãy điều chỉnh lại mức độ của 2 thanh trượt này và test thử bằng cách viết chữ vào ô bên dưới.

cach-giam-do-tre-ban-phim-tren-windows (9)

+ Bước 3: Sau khi tìm thấy mức Repeart delay và Repeart rate “lí tưởng” thì bạn bấm Apply => và OK để kết thúc. Đây thực chất là cách điều chỉnh tốc độ chuột nhé các bạn !

#3. Sử dụng tính năng Keyboard Troubleshooter

Windows cung cấp cho chúng ta một số công cụ hỗ trợ khắc phục sự cố trong quá trình sử dụng Windows 10, trong đó có cả công cụ phát hiện và sửa lỗi liên quan đến bàn phím. Vậy nên, nếu bạn đang gặp vấn đề về bàn phím thì không có lý do gì chúng ta lại bỏ qua công cụ này cả.

+ Bước 1: Mở Windows Settings lên bằng cách sử dụng tổ hợp phím Win + I trên bàn phím.

+ Bước 2: Tìm đến phần Update & Security => và chọn tính năng Troubleshoot.

cach-giam-do-tre-ban-phim-tren-windows (10)

+ Bước 3: Sau đó bạn bấm vào Additional troubleshooters, bạn tìm và bấm chọn Keyboard => chọn tiếp Run the troubleshooter để Windows thực hiện quá trình Fix lỗi của nó.

cach-giam-do-tre-ban-phim-tren-windows (11)

#4. Cập nhật lại Driver bàn phím

Đôi khi lỗi bàn phím bị trễ tín hiệu cũng có thể do driver bàn phím của nó đã lỗi thời, hoặc bị xung đột. Để cập nhật lại driver, bạn làm như sau:

+ Bước 1: Nhấn tổ hợp phím Win + X => sau đó nhấn vào Device Manager.

Hoặc một cách khác là nhấn chuột phải vào This PC trên màn hình Desktop => chọn Manage => chọn Device Manager.

cach-giam-do-tre-ban-phim-tren-windows (4)

+ Bước 2: Bạn tìm đến driver bàn phím => sau đó nhấp đúp chuột vào nó.

cach-giam-do-tre-ban-phim-tren-windows (5)

+ Bước 3: Bạn vào tab Driver => sau đó nhấn vào Update Driver.

cach-giam-do-tre-ban-phim-tren-windows (6)

+ Bước 4: Chọn Search automatically for drivers.

cach-giam-do-tre-ban-phim-tren-windows (7)

+ Bước 5: Đợi một lúc để Update Driver (nếu có).

NOTE: Nếu cách trên không có tác dụng thì bạn nên Update Driver thông qua Windows Update, hoặc tham khảo bài viết hướng dẫn cách update driver cho máy tính chuẩn nhất nhé.

  12 loại bàn phím cho lập trình viên (Phần 1)
  "Làm PM, theo anh không cần biết về code, nhưng phải hiểu về SQL, database, những khái niệm cơ bản của code"

#5. Đối với bàn phím không dây

Đây là cách sửa lỗi với bàn phím không dây. Nếu bạn sử dụng bàn phím có dây thì hãy bỏ qua cách này nhé.

cach-giam-do-tre-ban-phim-tren-windows (1)

+ Thay pin

Có thể bàn phím bị delay hoặc viết không ra chữ là do Pin đã cạn kiệt. Thay pin bàn phím hoặc sạc Pin cho bàn phím và thử lại xem vấn đề có được giải quyết không.

+ Kiểm tra kết nối

Bạn hãy thử gắn lại USB Receiver của bàn phím vào một khe USB khác. Nếu có thể, hãy đặt bàn phím gần với máy tính của bạn để đảm bảo kết nối được tốt nhất.

#6. Thay bàn phím mới

Và cuối cùng, nếu như đã thử hết cách rồi, và bạn cũng đã thử mang bàn phím đó kết nối sang một máy tính khác nhưng vẫn bị hiện tượng như vậy thì khả năng cao là bàn phím bị lỗi rồi. Bạn vui lòng xuống tiền mua một em bàn phím khác nhé

#7. Lời kết

Ok, trên đây là 5 cách giúp bạn kiểm tra và sửa lỗi bàn phím máy tính khi bị trễ, bị delay hiệu quả nhất. Ngoài những cách mà mình chia sẻ bên trên ra, nếu bạn còn biết thêm phương pháp nào hiệu quả khác nữa thì đừng quên chia sẻ lại cho mọi người thông qua khung comment bên dưới nhé.

CTV: Hoàng Tuấn – Blogchiasekienthuc.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 thế nào để Test Jersey Rest API với JUnit?

test jersey rest api
Làm thế nào để Test Jersey Rest API với JUnit?

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

Trong bài này tôi sẽ hướng dẫn các bạn cách viết Unit Test để test Jersey REST API sử dụng Jersey Test.

Một số kiến thức bạn cần nắm trước khi xem phần tiếp theo của bài viết này:

Test REST API cần test những gì?

Khi test một resource REST API, thông thường có một vài thứ cần test như sau:

  • HTTP response code : 200 OK, 201 Created, 204 NO Content, …
  • HTTP headers trong response: Content-Type, Content-Encoding, Content-Length, Content-Language, …
  • Payload (JSON, XML).
  Giới thiệu JUnit
  Liệu tôi có làm Junior Developer "mãn kiếp"?

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

Tạo Jersey Project

Tương tự như các bài viết trước, chúng ta sẽ tạo Jersey project với cấu trúc như sau:

Thêm thư viện Jersey test sau vào file pom.xml:

<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.test-framework.providers/jersey-test-framework-provider-grizzly2 -->         <dependency>             <groupId>org.glassfish.jersey.test-framework.providers</groupId>             <artifactId>jersey-test-framework-provider-grizzly2</artifactId>             <version>2.29</version>         </dependency>

Xây dựng Jersey Rest API

Giả sử chúng ta có các API sau:

Jersey implement các API như sau:

package com.gpcoder.api;

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.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.SecurityContext;

import com.gpcoder.model.Order;

// URI:
// http(s)://:(port)/// // http://localhost:8080/api/orders
@Path("/orders")
public class OrderService {

@GET
@Path("/{id}")
public Response get(@PathParam("id") int id) {
Order order = new Order();
order.setId(1);
order.setName("gpcoder");
return Response.ok(order).build();
}

@POST
public Response insert(Order order, @Context SecurityContext securityContext) {
int newOrderId = 999;
return Response.status(Status.CREATED).entity(newOrderId).build();
}

@PUT
@Path("/{id}")
public Response update(@PathParam("id") int id, Order order) {
return Response.ok().build();
}

@DELETE
@Path("/{id}")
public Response delete(@PathParam("id") int id) {
return Response.status(Status.NO_CONTENT).build();
}
}

Test Jersey Rest API với JUnit và JerseyTest

Để test Jersey REST API chúng ta sẽ sử dụng thư viện JUnit Test và Jersey Test .

package com.gpcoder.api;

import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;

import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import com.gpcoder.model.Order;

public class OrderServiceTest extends JerseyTest {

@Override
public Application configure() {
return new ResourceConfig(OrderService.class);
}

@Test
public void testGetById() {
Response response = target("/orders/1").request().accept(MediaType.APPLICATION_JSON).get();
assertEquals("Should return status 200", 200, response.getStatus());
assertNotNull("Should return user object as json", response.getEntity());
assertEquals("Http Content-Type should be: ", MediaType.APPLICATION_JSON,
response.getHeaderString(HttpHeaders.CONTENT_TYPE));
assertThat("Should return new order contains gpcoder string",
response.readEntity(String.class), containsString("gpcoder"));
}

@Test
public void testCreate() {
Order order = new Order(1, "gpcoder");
Response response = target("/orders").request().post(Entity.entity(order, MediaType.APPLICATION_JSON));
assertEquals("Should return status 201", 201, response.getStatus());
assertNotNull("Should return new order id", response.readEntity(Integer.class));
}

@Test
public void testUpdate() {
Order order = new Order(1, "gpcoder edited");
Response response = target("/orders/1").request().put(Entity.entity(order, MediaType.APPLICATION_JSON));
assertEquals("Should return status 200", 200, response.getStatus());
}

@Test
public void testDelete() {
Response response = target("/orders/1").request().delete();
assertEquals("Should return status 204", 204, response.getStatus());
}
}

Giải thích đôi chút về chương trình trên:

  • Đầu tiên, chúng ta tạo một class Test extend từ JerseyTest. Đây là bắt buộc nếu muốn test JAX-RS và Jersey-based applications sử dụng Jersey test framework.
  • Override phương thức configure() : chỉ định resource cần test.
  • Tiếp theo viết các method JUnit test.
  • Để call các REST API, chúng ta sẽ sử dụng phương thức target()request() để tạo WebTarget, Builder tương tự như cách sử dụng Jersey Client.
  • Cuối cùng gửi các request thông qua các phương thức: post()get()put()delete().

Trên đây là một số hướng dẫn cơ bản để test REST API sử dụng thư viện Jersey test. Trong bài viết tiếp theo, tôi sẽ hướng dẫn các bạn một thư viện khác rất mạnh mẽ để test web service là REST Assured.

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 IT hấp dẫn trên TopDev

Vì sao feedback rất quan trọng?

sự quan trọng của feedback
Vì sao feedback rất quan trọng?

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

Có một điều chắc các bạn cũng nhận ra, là khi làm việc với nhiều khách hàng Âu Mỹ hay Nhật, họ thường rất chịu khó đưa ra lời khen ngợi khi chúng ta làm gì đó tốt, thậm chí là chưa tốt, và họ cũng không ngần ngại chỉ trích hay góp ý khi có điều gì đó ngứa tai gai mắt.

Đây là một kĩ năng communication rất quan trọng. Gọi là Giving Feedback.

  10 Công cụ Go-To Tech dành riêng cho các Software Developer
  10 kênh Youtube học lập trình không thể bỏ qua dành cho Junior Web Developer / Designer

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


Feedback có thể hiểu là đưa ra ý kiến phản hồi cho một ai đó về một cái gì đó sau một chuyện gì đó.

Có 3 loại feedback thường thấy, đó là:

  • Positive Feedback: phản hồi dương tính, à nhầm mang tính tích cực, đưa ra để cho đối phương biết mình ghi nhận những cố gắng của họ, rằng đang làm tốt một việc gì đó, khích lệ họ để keep it up.
  • Constructive Feedback: phản hồi mang tính xây dựng, đưa ra với mục đích cho đối phương biết hành động của họ cần phải thay đổi.
  • Destructive Feedback: đây là thể loại constructive feedback phiên bản lỗi, được đưa ra một cách vội vã thiếu tế nhị, không đúng nơi đúng chỗ, hoặc đúng người nhưng sai thời điểm. Cũng là loại feedback phổ biến nhất ở trên đường, cũng như ở trên mạng. Tác dụng của nó là zero, còn tác hại thì vô cùng. Mình nghĩ người ta hay đưa ra kiểu feedback này chỉ vì ngứa mồm. Ở nhiều nơi mà cuộc sống khắc nghiệt, thì người đưa ra feedback có khả năng nhận được gói mát xa tẩm quất miễn phí chỉ cần trả tiền viện phí.

Ví dụ ở đoạn mở bài có nhắc tới, bạn làm gì cũng đc khách hàng khen, kể cả trễ deadline, thì đó gọi là positive feedback. Khi đồng đội mình hoàn thành dự án và launch thành công thì các sếp thường mở launch party và đọc tên từng người để ghi nhận công lao, đó là positive feedback. Coi Rap Việt ta thường thấy các bạn thí sinh shout out to my teacher Binz hay to anh em homie DCOD thì đó cũng là positive feedback.

Khi bạn thấy một ai đó làm gì sai, bạn muốn họ sửa, hoặc bạn tìm ra một con bug của một phần mềm nào đó và bạn viết bug report, bạn muốn đưa ra một ý tưởng gì đó để cải thiện, cũng lại coi Rap Việt bạn thấy Binz hay đưa ra phân tích về flow, vần của thí sinh, hay bạn thấy anh em WeBuild đưa ra feedback là ko biêt bao giờ huytd lại drop project, phần lớn trong số đó là constructive feedback mặc dầu tùy theo cách đưa ra feedback, nó sẽ trở thành destructive feedback.

Vậy thì phải đưa ra feedback như thế nào?

Có 2 yếu tố quan trọng khi đưa ra feedback đó là:

  • Be specific: đưa ra feedback đúng nơi đúng chỗ và đúng nội dung, và feedback như nào để người ta có thể take action được. Bạn không nên thấy một người mới start một cái side project và bay vào nói “Để xem khi nào anh drop”, vì nó ko add thêm value gì cho anh ấy cả, và khi nghe feedback như thế thì bạn expect họ sẽ làm gì?
  • Be timely: Thường thì real time feedback là tốt nhất, nhưng nếu tình thế ko cho phép thì cũng nên đưa ra feedback trong vòng 48 tiếng đồng hồ (ví dụ các bạn gái khi thấy người yêu mãi chơi game ko lo xếp quần áo, thì thay vì chạy tới rút dây máy PS5, nên bình tĩnh chờ người ta đánh xong ván đã, rồi hãy bắt úp mặt vô tường quỳ gối, nhưng cũng đừng nên chờ 1 tuần sau mới lôi ra nhắc lại chuyện cũ để rồi bị nói là nắng mưa vô cớ).

Để đưa ra feedback một cách tốt hơn, người ta nghĩ ra rất nhiều mô hình, các bạn có thể search thêm với từ khóa “Feedback Model”, hoặc đọc thêm tại đây hoặc đây.

Nhìn chung, các mô hình này đều xoay quanh 4 yếu tố:

  • Context: Nói về tình huống khi bạn nhìn thấy sự việc xảy ra.
  • Behavior: Nói về hành vi của những người liên quan đế vấn đề bạn đang feedback. Nói một cách khách quan nhất, và đừng có đánh giá gì về hành động đó cả.
  • Impact: Nói về ảnh hưởng mà hành động đó gây ra, và nó tác động đến bạn hoặc những người xung quanh như nào.
  • Follow Up: Đưa ra gợi ý về những gì người nhận feedback cần hoặc nên làm.

Ví dụ, bạn đang review code và phát hiện ra một vấn đề gì đó nên sửa:

  • “Code như cức, senior rồi mà còn code như này à?!” – Destructive feedback
  • “Tôi thấy chỗ này bạn xài let với const hơi lộn xộn, nó không ảnh hưởng gì nhiều về mặt logic nhưng làm vậy code style sẽ trở nên thiếu đồng nhất, tôi nghĩ bạn nên sửa hết về let, ý bạn sao?” – Constructive feedback

Một ví dụ khác, bạn Tèo vừa bỏ ra 1 ngày trời để setup mấy cái github actions giúp tự động chạy unit test trên mỗi PR của team, giúp nâng cao chất lượng code của cả team, là một teammate, bạn có thể làm gì?

  • Lên slack và post: “Shout out to my Tèo homie, cái github actions tự động chạy test của bạn ấy giúp cho cả team mình thấy yên tâm hơn khi fix code. Keep it up man!” – Positive feedback
  • Im lặng ko nói gì – No feedback = Destructive feedback, đến kì lương sau thì ko ai thấy Tèo đi làm nữa.

Một ví dụ khác nữa, lên WeBuild thấy một bạn thành viên mới post lên rằng: “Hi @channel, mình là mem mới, rất vui được làm quen với các bạn”, phản ứng của mọi người là:

  • Đồng loạt thả những cái reaction giận dữ, vào comment: “Bớ admin ơi có đứa tag channel!!!”, “Bà nội mày ai cho mày tag channel!!!!”, rồi thi nhau leave room – Destructive feedback, bị chửi bạn mem mới kia sẽ lồng lộn lên chửi lại rồi bỏ WeBuild mà đi, có khi đi nơi khác mà chửi WeBuild ko thương tiếc.
  • Vào comment hoặc ping riêng một cách nhã nhặn: “Bạn ơi, vừa rồi mình thấy bạn tag channel ở #general, đây là public channel nên có mấy nghìn thành viên lận, tag vậy sẽ làm phiền mọi người đấy, bạn edit lại đi nha.” – Constructive feedback, nếu nhận được phản hồi như thế này, mình không nghĩ có ai cảm thấy offense và sẽ vui vẻ sửa sai ngay.

Các bạn thấy đấy, việc đưa ra feedback là rất quan trọng và cần thiết, và đưa ra feedback như nào lại quan trọng không kém. Cái ranh giới giữa constructive feedback và destructive feedback nó chỉ cách nhau một cái ngứa mồm và một nhịp cảm xúc.

Be a good communicator, don’t be that person.

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 các vị trí CNTT hấp dẫn trên TopDev

Định nghĩa request body và response với RAML

request body và response
Định nghĩa request body và response với RAML

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

Đối với các request với HTTP method là POST, PUT, DELETE, thông thường chúng ta sẽ cần định nghĩa request body. Với RAML thì chúng ta sẽ định nghĩa cấu trúc của request body như thế nào và làm thế nào để định nghĩa response với RAML. Trong bài viết này, chúng ta hãy cùng nhau tìm hiểu các bạn nhé!

  Định nghĩa request URL với RAML
  10 Java Web Framework tốt nhất

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

Giả sử mình định nghĩa một request để thêm mới thông tin sinh viên với nội dung ban đầu như sau:

#%RAML 1.0
baseUri: https://localhost:8081/api
title: Student Management System
version: 1.0

/students:
post:
description: Add new student

Để định nghĩa request body cho request này, chúng ta sẽ khai báo thêm section body với content-type, kiểu dữ liệu và có thể thêm example cho request body này nữa. Ví dụ như sau:

/students:
post:
description: Add new student
body:
application/json:
type: Student
example: { "id" : 5, "name" : "Khanh" }

Như các bạn thấy, mình đã định nghĩa content-type cho data trong request body trong ví dụ này của mình là application/json với kiểu dữ liệu là Student như sau:

types:
Student:
type: object
properties:
id:
required: true
type: integer
name:
required: true
type: string

Để định nghĩa response cho một request trong RAML, chúng ta sẽ sử dụng section responses. RAML cho phép chúng ta định nghĩa response cho từng HTTP  status code và với mỗi response, tương tự như request body, chúng ta cũng có thể định nghĩa response body. Ví dụ như sau:

/students:
post:
description: Add new student
body:
application/json:
type: Student
example: { "id" : 5, "name" : "Khanh" }
responses:
201:
body:
application/json:
type: String
example: "Created"

Như các bạn thấy, ngay sau khi khai báo section cho HTTP status code, chúng ta sẽ khai báo section body để khai báo nội dung của response body. Chúng ta cũng có thể khai báo content-type, kiểu dữ liệu, example tương tự như request body.

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

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

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

Tìm hiểu cơ chế Lazy Evaluation của Stream trong Java 8

lazy evaluation
Tìm hiểu cơ chế Lazy Evaluation của Stream trong Java 8

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

Trong bài viết “Giới thiệu về Stream API trong Java 8” , chúng ta đã tìm hiểu về các đặc điểm, các làm việc của Stream trong Java 8. Ở bài viết này, tôi muốn giải thích kỹ hơn về cơ chế Lazy Evaluation của Stream trong Java 8.

  10 tips để trở thành Java Developer xịn hơn
  Những mã xấu mà Java 8 có thể khử

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

Như chúng ta đã biết, Stream có một đặc điểm rất quan trọng là cho phép tối ưu hóa hiệu xuất của chương trình thông qua cơ chế lazy evaluation, nghĩa là chúng không được thực hiện cho đến khi cần thiết. Các hoạt động tính toán trên source data chỉ được thực hiện khi một terminal operation được khởi tạo và các source element chỉ được sử dụng khi cần.

Hãy xem ví dụ 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
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Stream;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
class Employee {
    String name;
    String department;
    int salary;
}
class EmployeeRepository {
    private static final Map<Integer, Employee> employees = new HashMap<>();
    static {
        employees.put(1, new Employee("gpcoder 1", "A", 50));
        employees.put(2, new Employee("gpcoder 2", "B", 100));
        employees.put(3, new Employee("gpcoder 3", "A", 150));
        employees.put(4, new Employee("gpcoder 4", "B", 200));
    }
    
    public Employee findById(Integer id) {
        System.out.println("findById: " + id);
        return employees.get(id);
    }
}
class EmployeeFilter {
    
    public static Predicate<Employee> filterDepartmentEqualsWith(String department) {
        return e -> {
            System.out.println("filterDepartmentEqualsWith: " + e);
            return e.getDepartment().equals(department);
        };
    }
    
    public static Predicate<Employee> filterSalaryGreaterThan(int salary) {
        return e -> {
            System.out.println("filterSalaryGreaterThan: " + e);
            return e.getSalary() >= salary;
        };
    }
}
public class Java8StreamDeeply {
    
    public static void main(String[] args) {
        EmployeeRepository employeeRepository = new EmployeeRepository();
        
        Integer[] empIds = { 1, 2, 3, 4 };
        
        Stream.of(empIds)
          .map(employeeRepository::findById)
          .filter(EmployeeFilter.filterSalaryGreaterThan(100))
          .filter(EmployeeFilter.filterDepartmentEqualsWith("A"))
          .findFirst();
    }
}

Chạy chương trình trên, chúng ta có kết quả như sau:

1
2
3
4
5
6
7
8
findById: 1
filterSalaryGreaterThan: Employee(name=gpcoder 1, department=A, salary=50)
findById: 2
filterSalaryGreaterThan: Employee(name=gpcoder 2, department=B, salary=100)
filterDepartmentEqualsWith: Employee(name=gpcoder 2, department=B, salary=100)
findById: 3
filterSalaryGreaterThan: Employee(name=gpcoder 3, department=A, salary=150)
filterDepartmentEqualsWith: Employee(name=gpcoder 3, department=A, salary=150)

Như bạn thấy, chương trình của chúng ta có 4 phần tử nhưng chỉ 3 phần tử được thực thi. Tại sao vậy?

Trong ví dụ trên, tôi sử dụng 3 Intermediate operations: 1 map() và 2 filter() operations. Chúng ta có 4 phần tử ở Stream source, mỗi phần tử có thể sẽ được thực thi 1 lần qua tất cả intermediate operation.

Đầu tiên, nó sẽ kiểm tra tất cả các operation trên phần tử có id là 1. Vì salary của nó không thõa filter salary, nên xử lý sẽ chuyển sang phần tử kế tiếp – id là 2. Không thực hiện trên filter deparment.

Tiếp theo, id 2 chỉ thõa mãn điều kiện salary, không thõa mãn điều kiện department, nên xử lý chuyển sang phần tử kế tiếp – id là 3.

Tại id 3, thõa mãn tất cả điều kiện ở trên và Stream evaluate yêu cầu Terminal Operations findFirst() và trả về kết quả.

Các operation trên các phần tử còn lại sẽ không được thực thi – id 4.

Có thể thấy rằng, Stream hoạt động tuần tự trên từng phần tử của source, duyệt qua tất cả các immediate operations, rồi đến terminal operation, cuối cùng mới chuyển sang phần tử kế tiếp (có thể không chuyển sang phần tử kế tiếp nếu đã thõa mãn mong muốn của terminal operation).

Tóm lại, quá trình xử lý các Stream một cách lười biếng (lazy) cho phép tránh việc kiểm tra tất cả dữ liệu khi không cần thiết. Cách làm này giúp cho Stream hoạt động rất hiệu quả khi có nhiều intermediate operation và nguồn dữ liệu là lớn.

Bài viết đến đây là hết, sau bài này hy vọng các bạn hiểu rõ hơn về Stream trong Java 8 và vận dụng nó thích hợp để đạt được hiệu quả tốt hơn.

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 các vị trí CNTT hấp dẫn trên TopDev

Định nghĩa request URL với RAML

request url
Định nghĩa request URL với RAML

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

Trong bài viết trước, mình đã giới thiệu với các bạn về RAML để định nghĩa API spec. Trong bài viết này, mình sẽ hướng dẫn các bạn chi tiết hơn cách định nghĩa request URL với RAML như thế nào các bạn nhé!

  cURL là gì? Cách sử dụng Curl
  How to Design System like TinyURL – P1

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

Để làm ví dụ cho bài viết này, đầu tiên, mình sẽ tạo mới một tập tin .raml với thông tin về API quản lý sinh viên bao gồm thêm, xoá, sửa, tìm kiếm với nội dung ban đầu như sau:

#%RAML 1.0
baseUri: https://localhost:8081/api
title: Student Management System
version: 1.0

Chúng ta sẽ định nghĩa một số request như sau:

  • GET /students để lấy danh sách sinh viên
  • POST /students để thêm mới sinh viên
  • PUT /students/{id} để cập nhập một sinh viên với id được truyền trong request
  • DELETE /students/{id} để xoá một sinh viên với id được truyền trong request
  • GET /students/find-by-name?name=<student-name>
  • GET /students/find-by-ids?id=<id1>,<id2>

Với những request như trên, các bạn có thể định nghĩa một root request “/students” như sau:

/students:

Các bạn cứ hình dung một request URL sẽ chia thành nhiều cấp từ trái sang phải. Ví dụ như request /api/students/find sẽ có 3 cấp là api rồi đến students rồi đến find. Các cấp này ngăn cách bởi dấu “/”. Mỗi cấp sẽ là một level trong tập tin .raml theo thứ tự đó nên trong ví dụ trên của mình, root request cho tất cả các request sẽ là “/students”.

 

Cho root request này, chúng ta có 2 request là GET và POST để lấy thông tin tất cả sinh viên và thêm mới sinh viên, nên các bạn chỉ cần khai báo những request này như sau:

/students:
get:
post:

Các bạn có thể thêm description cho mỗi request nếu muốn, ví dụ như:

/students:
get:
description: Get all students
post:
description: Add new student

Tiếp theo, chúng ta có 2 request với /students/{id} với PUT và DELETE HTTP method, dùng để cập nhập và xoá thông tin của một sinh viên nào đó. Vì chúng ta đã định nghĩa root request với “/students” rồi nên giờ các bạn chỉ cần định nghĩa cho 2 request mới này như sau:

/students:
get:
post:

/{id}:
put:
description: Update information for a student
delete:
description: Delete information of a student

Các bạn có thể định nghĩa thêm thông tin của các path parameter, thông tin về mục đích của path parameter, kiểu dữ liệu là gì, example về giá trị của chúng nữa. Để làm được điều này, chúng ta sẽ dùng section uriParameters. Ví dụ mình có thể định nghĩa thông tin cho path parameter {id} trong ví dụ trên như sau:

/students:
get:
description: Get all students
post:
description: Add new student

/{id}:
uriParameters:
id:
description: Id of the student
type: string
example: "1"
put:
description: Update information for a student
delete:
description: Delete information of a student

Đối với request /students/find-by-name?name=<student-name>, chúng ta cần định nghĩa thêm section /find-by-name với root request là “/students” như sau:

/students:
get:
description: Get all students
post:
description: Add new student

/{id}:
uriParameters:
id:
description: Id of the student
type: string
example: "1"
put:
description: Update information for a student
delete:
description: Delete information of a student

/find-by-name:
get:
description: Find student by name

HTTP method của request này là GET và mình cũng đã thêm description cho request này.

Đối với request /students/find-by-name này, chúng ta có thêm request parameter tên là name. Chúng ta có thể định nghĩa thông tin request parameter này như sau:

/students:
get:
description: Get all students
post:
description: Add new student

/{id}:
uriParameters:
id:
description: Id of the student
type: string
example: "1"
put:
description: Update information for a student
delete:
description: Delete information of a student

/find-by-name:
get:
description: Find student by name
queryParameters:
name: 
description: Name of student
type: string
example: "Khanh"

Như các bạn thấy, mình sử dụng section queryParameters để định thông tin cho tất cả các request parameter của request. Request parameter trong ví dụ này của mình có kiểu dữ liệu String. Các bạn có thể định nghĩa request parameter này có bắt buộc hay không sử dụng thuộc tính “required: false” hoặc sử dụng question mark như sau:

queryParameters:
name?: 
description: Name of student
type: string
example: "Khanh"

Trong ví dụ của mình thì request parameter name là bắt buộc các bạn nhé!

Đối với những request có matrix parameter như /students/find-by-ids?id=<id1>,<id2> thì các bạn có thể định nghĩa matrix parameter đó với type là array. Ví dụ như sau:

/students:
get:
description: Get all students
post:
description: Add new student

/{id}:
uriParameters:
id:
description: Id of the Student
type: string
example: "1"
put:
description: Update information for a student
delete:
description: Delete information of a student

/find-by-name:
get:
description: Find student by name
queryParameters:
name: 
description: Name of student
type: string
example: "Khanh"
/find-by-ids:
get:
description: Find list of students by a list of Ids
queryParameters:
ids: 
description: List of Ids
type: number[]
example: "1,2,3"

Toàn bộ nội dung của tập tin .raml của ví dụ trong bài viết này như sau:

#%RAML 1.0
baseUri: https://localhost:8081/api
title: Student Management System
version: 1.0

/students:
get:
description: Get all students
post:
description: Add new student

/{id}:
uriParameters:
id:
description: Id of the Student
type: string
example: "1"
put:
description: Update information for a student
delete:
description: Delete information of a student

/find-by-name:
get:
description: Find student by name
queryParameters:
name: 
description: Name of student
type: string
example: "Khanh"
/find-by-ids:
get:
description: Find list of students by list of Ids
queryParameters:
ids: 
description: List of Ids
type: number[]
example: "1,2,3"

Giới thiệu Castle Mock – Mock REST APIs và SOAP web-services

castle mock
Giới thiệu Castle Mock – Mock REST APIs và SOAP web-services

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

Trong quá trình phát triển hệ thống hoặc quá trình testing, một trong những vấn đề khó khăn là khi hệ thống của bạn cần tích hợp với một bên thứ ba (3rd party). Do sử dụng API của bên thứ ba nên chúng ta có thể gặp một số vấn đề sau:

  • Bên thứ ba không có hoặc không cung cấp hệ thống test cho chúng ta.
  • Bên thứ 3 đang phát triển API song song với chúng ta hoặc chưa hoàn thành API cho chúng ta sử dụng.
  • Không thể gọi API thật để test: gặp vấn đề về chi phí và bảo mật.
  • Gọi service của bên thứ ba để viết Unit Test rất chậm và đôi khi service của họ die dẫn đến Unit Test của chúng ta failed không mong muốn.
  AspectMock là gì? Tại sao dùng AspectMock với Codeception
  Hướng dẫn tạo mock API Server với Post Man

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

Để giải quyết vấn đề này, mình cần thu thập API document của họ, và dựng nên con mock service, trả về đúng những trường hợp cần sử dụng trong requirement API document và để team tích hợp.

Trong bài viết này mình sẽ giới thiệu về 1 Mock service rất dễ sử dụng là Castle Mock.

Giới thiệu Castle Mock

Castle Mock là một ứng dụng web cung cấp chức năng để giả lập API RESTful và SOAP web service. Chức năng này cho phép các developer phía client có thể giả lập các behavior và response ở phía server.

Một số tính năng nỗi bật của Castle Mock:

  • SOAP & REST: Có thể Mock cho cả SOAP and REST. Có thể được cấu hình bằng cách import các file định nghĩa service như: WSDL, WADL, Swagger và RAML. Các web service được xác định trong các file cấu hình sẽ được Castle Mock giả lập một cách tự động.
  • Proxy và record responses: Castle Mock có thể được sử dụng như một proxy giữa Client và Server. SOAP và REST có thể được mock hoặc chuyển tiếp đến service thật. Phản hồi (response) từ các yêu cầu được chuyển tiếp có thể được ghi lại tự động và được sử dụng để tạo các phản hồi giả (mocked response).
  • Logging: Tất cả các request gửi đến và response gửi đi sẽ được ghi lại, giúp chúng ta dễ dàng theo dõi cũng như debug khi cân thiết.
  • Easy installation: Castle Mock được xây dựng bằng Java và bản thân ứng dụng được dễ dàng triển khai trên máy chủ Apache Tomcat thông qua WAR file. Ngoài ra, Castle mock cũng dễ dàng được setup và deploy trên Docker.
  • Open source: Castle Mock hoàn toàn miễn phí và là nguồn mở (Giấy phép Apache 2.0). Source code của nó có thể được tìm thấy trên Github.

Download và cài đặt Castle Mock

Yêu cầu cài đặt các phần mềm:

Hướng dẫn cài đặt Java 8

Các bạn xem lại bài viết “Hướng dẫn cài đặt JDK“.

Cài đặt và cấu hình Tomcat Server

Các bạn xem lại bài viết “Triển khai ứng dụng Jersey REST Web service lên Tomcat Server“.

Download và cài đặt Castle Mock

Truy cập link sau để download Castle Mock: https://castlemock.com/use-castle-mock/

Sau khi đã download thành công file .war, chúng ta tiến hành deploy nó lên Apache Tomcat server.

Mặc định Tomcat chỉ cho phép upload tối đa 50MB. Do file castlemock lớn hơn nên mình cần config lại limit size cho phép upload lên tomcat server. Các bạn mở file webapps/manager/WEB-INF/web.xml trong thư mục Tomcat.

Truy cập link sau và deploy castle mock: http://localhost:8090/manager

  • Context Path: /castlemock
  • Chọn file castlemock.war đã download ở trên.

Sau khi đã deploy xong, các bạn truy cập địa chỉ sau: http://localhost:8090/castlemock

Bạn sẽ được yêu cầu nhập username và password truy cập ứng dụng castle mock:

1
2
Username: admin
Password: admin

Sử dụng Castle Mock

Tạo Mock project và tạo các mock REST and SOAP APIs.

REST project

Create a REST project

Trên trang Overview, click “New project” button để bắt đầu tạo một project mới. Nhập tên project, description và chọn chọn loại project là REST.

Tiếp theo, chọn project đã tạo:

Upload API specifications

Mock service có thể được tạo bằng nhiều cách. Sau khi đã tạo project, chúng ta có thể tạo các mock service thủ công hoặc upload file đặc tả API (API specification) nếu đã được định nghĩa từ trước.

Castle Mock hỗ trợ các loại API specification: Swagger, RAML, WADL. Để đơn giản trong bài này, tôi sử dụng Swagger.

Giả sử chúng ta cần tạo mock các API của Swagger sau: http://petstore.swagger.io/ . File mô tả các API này được định nghĩa trong file swagger.json tại link https://petstore.swagger.io/v2/swagger.json

Click button Upload và chọn Swagger:

Chúng ta có 2 lựa chọn: nhập link đến file đặc tả API hoặc upload một file mới. Sau đó check chọn “Generate response for each operation” để swagger tự tạo response cho mỗi API.

Click button Link Swagger hoặc Upload để tạo mock service.

Click lên tên Application:

Create mocked responses

Click tên Resource “/user” -> tên Method “createUser”, chúng ta có kết quả sau:

Sau khi import và check “Generate response …”, Castle Mock giúp chúng ta tạo 1 response như trên.

Một Method có thể có nhiều Response, mỗi Response có Name, HTTP status code, Header và resposne message.

Chúng ta có thể tạo một response mới bằng cách click vào button Create Resposne như sau:

Chúng ta có 2 response:

Update method – Response strategy

Chúng ta có thể tạo nhiều response, như vậy Castle Mock lựa chọn response nào để trả kết quả về cho request? Đó chính là cấu hình response strategy.

Castle Mock hỗ trợ các loại response strategy:

  • Random (ngẫu nhiên): chiến lược này lựa chọn một mock response ngẫu nhiên.
  • Sequence (tuần tự): chiến lược này lựa chọn một mock response theo trình tự. Trình tự được xác định theo thứ tự các mock response được tạo. Trình tự sẽ bắt đầu lại từ đầu khi nó đã đến response cuối cùng.
  • Ngoài ra còn có: Query match, XPath match, JSON Path match, Header Query match.

Để cấu hình Response Strategy, click button “Update method“:

Update method – Method type

Castle Mock hỗ trợ tất cả Method type: GET, PUT, POST, DELETE, …

Update method – Method status

Một mock api có một mode. Mode sẽ xác định cách mock web service sẽ hoạt động như thế nào. Các mode được Castle mock hỗ trợ:

  • Mocked : mode này sẽ sử dụng các mock response đã định nghĩa.
  • Disabled : mode này làm service bị disable. Phía end user sẽ nhận được thông báo lỗi nếu cố gắng gọi một ws bị vô hiệu hóa.
  • Forward requests: mode này sẽ chuyển tiếp sẽ chuyển tiếp tất cả các request đến điểm cuối bên ngoài (service thật). Mode này có thể được sử dụng khi chỉ một số ws bị mock, trong khi phần còn lại sẽ gọi đến ws thật.
  • Record responses : mode này sẽ chuyển tiếp tất cả các request đến điểm cuối bên ngoài và tạo phản hồi giả (mock response) cho các response được trả về từ điểm cuối bên ngoài.
  • Recording once : mode này sẽ thực hiện giống như mode Record response, nhưng sẽ chỉ thực hiện một lần. Khi đã xong, ws sẽ chuyển sang chế độ Mocked thay thế.
  • Echo : mode này sẽ trả về request như là một response.

Update method – Simulate netword deplay

Các request trên internet có độ trễ (deplay) là không tránh khỏi, chúng ta có thể dễ dàng mô phỏng độ trễ phản hồi response một cách dễ dàng thông qua option này.

Test các Mock REST API được tạo bởi Castle Mock với Postman

Để test Mock REST API được tạo bởi Castle Mock, các bạn có thể click lên Resource và lấy thông tin resource như sau:

Mở Postman và gọi đến REST API trên, chúng ta sẽ lần lượt nhận được response status 200 và 400.

SOAP project

Create a SOAP project

Tương tự như tạo REST Project, các bạn chọn loại project là SOAP.

Import WSDL file

Mock SOAP web service được tạo bằng cách import file WSDL – file mô tả SOAP web service. Trên trang SOAP project, click “Upload WSDL” button để upload một file WSDL hoặc trỏ đến URL của file WSDL.

Để đơn giản tôi sẽ sử dụng API Calculator từ http://www.dneonline.com/calculator.asmx với link WSDL như sau: http://www.dneonline.com/calculator.asmx?WSDL

Sau khi Link WSDL:

Chúng ta có thể xem chi tiết API đã import với các response được tạo:

Create mocked responses

Tương tự như REST, chúng ta có thể tạo nhiều Mock response nếu cần.

Test các Mock SOAP API được tạo bởi Castle Mock với SOAP UI

Để test Mock SOAP API được tạo bởi Castle Mock, các bạn có thể click lên tên Project và lấy thông tin URL của file WSDL như sau:

Mở SOAP UI, và import file mock WSDL trên để test.

Bài viết đến đây là hết. Chúc các bạn thành công trong việc sử dụng hiệu quả Mock service :).

Ah, ngoài ra còn một công cụ khác cũng có tính năng tương tự là mountebank. Công cụ này được xây dựng trên nền node.js, các bạn có thể tìm hiểu thêm document trên trang chủ của mountebank nếu thích.

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 các vị trí IT hấp dẫn trên TopDev

Offline token với Keycloak

offline token
Offline token với Keycloak

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

Offline access là một tính năng của OpenID Connect được định nghĩa tại https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess. Nó giúp cho application với offline token (một loại của refresh token) có thể lấy access token và sử dụng resource mà không cần user phải đăng nhập trong thời gian dài hoặc mãi mãi. Keycloak hỗ trợ chúng ta làm việc với offline access bằng cách sử dụng offline token. Cụ thể như thế nào? Chúng ta hãy cùng nhau tìm hiểu trong bài viết này các bạn nhé!

  Authorization Code grant type với Proof Key for Code Exchange (PKCE) trong OAuth 2.1
  C Token là gì? Cú pháp trong lập trình C/C++

Xem thêm nhiều việc làm NextJS lương cao trên TopDev

Để làm ví dụ, mình sẽ tạo mới một client với grant type Authorization Code trong Keycloak như sau:

 

Điều đầu tiên các bạn cần phải biết là làm thế nào chúng ta lấy được offline token.

Rất đơn giản, trong request lấy authorization code cho client, chúng ta cần truyền thêm scope là offline_access là được:

 

Keycloak sẽ hỏi chúng ta có cho phép Client Application Offline Access hay không?

Nếu các bạn đồng ý thì sau khi có authorization code, request lấy access token cho client này:

 

parse nội dung của refresh token, các bạn sẽ thấy nội dung payload như sau:

Type của token này là Offline thay vì Refresh và các bạn có thể thấy, không có claim “exp” với expiration time như khi chúng ta parse access token:

 

Chúng ta có thể sử dụng offline token này để lấy access token mới tương tự như refresh token.

Ví dụ như sau:

Điểm khác biệt giữa offline token và refresh token là không có expiration time cho offline token.

 

Mặc định thì offline token là nó sẽ luôn valid dù user không đăng nhập hoặc server bị restart, chỉ trừ khi nó bị revoke. Tuy nhiên, các bạn cần sử dụng offline token này ít nhất là một lần trong khoảng thời gian mặc định là 30 ngày, kể từ lần sử dụng gần nhất. Đó là bởi vì, một offline token sẽ associate với một offline session. Và offline session này chỉ có thời gian chờ (idle time) mặc định là 30 ngày như mình nói ở trên. Ở Realm level thì giá trị 30 ngày này được cấu hình trong tab Tokens của Realm Settings, field Offline Session Idle:

Ở tab Tokens này, như các bạn thấy, chúng ta còn có 1 field khác liên quan đến offline session nữa, tên là Offline Session Max Limited. Ý nghĩa của field này là nếu các bạn enable, offline token sẽ bị expired trong thời gian mặc định là 60 ngày, dù chúng ta có sử dụng offline token này bao nhiêu lần đi chẳng nữa:

Các bạn có thể thay đổi các cấu hình liên quan đến offline session ở Realm level nếu muốn, các client sẽ kế thừa cấu hình này. Còn nếu muốn cấu hình cụ thể cho một client nào đó thì hãy expand phần Advance Settings trong mỗi client:

chúng ta có thể thay đổi cấu hình của Client Offline Session Idle và Client Offline Session Max ở đây.

Các bạn có thể xem tất cả các offline token của một client bằng cách vào tab Offline Access của client đó

Tối Ưu Hóa Quy Trình Kiểm Soát Chất Lượng Với 7 Công Cụ QC

7 công cụ qc
Tối Ưu Hóa Quy Trình Kiểm Soát Chất Lượng Với 7 Công Cụ QC

7 công cụ QC đã và đang trở nên quen thuộc với những nhân viên đảm nhận ở vị trí Quality Control trong mỗi nhà máy sản xuất. Và dĩ nhiên chúng là cánh tay đắc lực giúp doanh nghiệp tiết kiệm chi phí vận hành khi đề ra mục tiêu chinh phục khách hàng. Ngày nay có không ít doanh nghiệp đã và đang ứng dụng 7 công cụ QC. Đây được xem là bài toán thông minh  giúp các doanh nghiệp quy mô vừa – nhỏ, thậm chí là các tập đoàn đa quốc gia giải quyết tối ưu những vấn đề về quản trị chi phí vận hành sản phẩm, dịch vụ. 

7 công cụ qc
7 công cụ qc

Công cụ quản lý chất lượng là gì?

QC (Quality Control) hay còn gọi là kiểm soát chất lượng là quy trình quan trọng để kiểm tra, đánh giá và vận hành thử trước khi một sản phẩm/ dịch vụ nào đó chạm tới tay người tiêu dùng. Liệu doanh nghiệp có thể tối ưu hóa hoạt động kinh doanh nhờ sử dụng công cụ kiểm soát chất lượng? 

Hiện nay, hoạt động kiểm soát chất lượng được ứng dụng trong nhiều lĩnh vực kinh tế khác nhau, từ quản lý công nghiệp đến kinh doanh thương mại. Bất kể doanh nghiệp quy mô vừa – nhỏ hay đến các tập đoàn lớn đều cho rằng quản lý chất lượng là một trong những khâu yếu tố quyết định việc sống còn của doanh nghiệp.

  Dù là nhân viên hay ông chủ, bạn cũng cần phải nắm 4 nguyên tắc này để nâng cao chất lượng công việc
  5 tips cải tiến chất lượng phát triển Mobile App

7 công cụ QC phổ biến được các doanh nghiệp đánh giá cao hiện nay

 Hiện nay, các công ty sử dụng tới 7 công cụ QC khác nhau để theo dõi, phân tích và đánh giá chất lượng của sản phẩm hoặc dịch vụ.

1. Lưu đồ (Flowchart)

Việc ai là cha đẻ phát minh ra lưu đồ vẫn là một ẩn số. Song ngày nay lưu đồ được áp dụng rộng rãi vì nó tóm tắt được các bước của một quy trình, có liên quan chặt chẽ với nhau để chỉ ra hoạt động hiệu quả trong hoạt động thực tế. Việc sử dụng công cụ QC này sẽ giúp nhân viên vận hành sản phẩm theo một quy trình cụ thể, rõ ràng và khoa học hơn. 

Lưu đồ dùng để kiểm soát quy trình hỗ trợ khách hàng

2. Biểu đồ mật độ phân bố (Histogram)

Về tổng thể thì đây là biểu đồ dạng cột đơn giản thể hiện tần suất của sản phẩm/dịch vụ xuất hiện ở thị trường nào đó. Qua đó nhân viên QC có thể đánh giá tình hình phân bố của sản phẩm/ dịch vụ. Và trên cơ sở này để có những can thiệp kịp thời để đảm bảo tình hình kinh doanh, sản xuất nhờ sử dụng công cụ QC này. 

Biểu đồ mật độ tần suất số lần phản ứng

3. Biểu đồ Pareto (Pareto Chart)

Là biểu đồ kết hợp đơn giản trong đó các đối tượng được sắp xếp từ tần số cao nhất đến tần số thấp nhất. Pareto cho phép các nhà phân tích kinh tế quan sát giá trị tuyệt đối đại diện cho nguyên nhân của sai số trong cột. Đồng thời, phần trăm lỗi tích lũy cũng được hiển thị dưới dạng một dòng.

4. Phiếu kiểm tra (Check sheet)

Việc thu thập, ghi chép dữ liệu từ phiếu kiểm tra đóng vai trò quan trọng trong việc đánh giá, đưa ra hướng giải quyết thích hợp. Phiếu kiểm tra được sử dụng linh hoạt từ việc điều tra nguyên nhân sản phẩm bị trả lại, kiểm tra, tìm nguyên nhân gây ra lỗi cho đến kiểm tra xác nhận trước khi trưng cầu ý kiến khách hàng. 

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

5. Biểu đồ quan hệ nhân quả (Cause & Effect Diagram)

Khi có sự cố phát sinh về chất lượng thì việc áp dụng biểu đồ quan hệ nhân quả sẽ giúp nhân viên QC tìm ra được nguyên nhân cội nguồn nằm ở đâu.  Trên thực tế, một vấn đề có thể xuất phát từ nhiều nguyên nhân khác nhau và ở chúng có sự phân cấp với nhau. Ví dụ như nguyên nhân thứ cấp gián tiếp xuất phát từ nguyên nhân thứ cấp trực tiếp, và tất cả đều xuất phát từ nguyên nhân gốc. Việc áp dụng biểu đồ quan hệ nhân quả sẽ giúp nhân viên QC dễ điều tra được sự cố của sản phẩm đó bắt nguồn từ đâu và đưa ra hướng giải quyết kịp thời. 

6. Biểu đồ phân tán (Scatter Diagram)

Mối tương quan giữa nguyên nhân và kết quả hoặc chất lượng bị ảnh hưởng bởi các yếu tố được thể hiện bằng biểu đồ này. Có nhiều yếu tố tác động qua lại và có tính kết hợp ảnh hưởng đến chất lượng của sản phẩm hay dịch vụ. Biểu đồ này có thể mô tả tình hình chất lượng bằng hai hay nhiều đối tượng cùng một lúc. 

7. Biểu đồ kiểm soát (Control Charts)

Biểu đồ kiểm soát được phát triển từ biểu đồ chạy (R – Chart), nhưng được thêm phần giới hạn kiểm soát trên và kiểm soát dưới. Cộng thêm công thức tính năng lực quá trình (Cp, Cpk) giúp nhân viên QC dễ dàng phân tích quan sát quá trình đó có nằm trong thông số có thể chấp nhận được hay không. 

Tìm việc làm QA QC lương cao trên TopDev

Tầm quan trọng của việc ứng dụng công cụ quản lý chất lượng trong sản xuất kinh doanh

Bất kỳ một công ty sản xuất muốn đưa sản phẩm/ dịch vụ của mình tiếp cận người dùng ở phân khúc thị trường nào đó sẽ không thể bỏ qua khâu kiểm soát chất lượng. Hay nói cách khác đầu tư vào đội ngũ QC (Quality Control) luôn đóng vai trò quan trọng giúp công ty  đó cho ra đời những sản phẩm hoàn hảo nhất đến khách hàng của mình. 

Thông thường đội QC sẽ đảm nhận vai trò khi làm việc trực tiếp tại nhà máy, phân xưởng và giám sát chặt chẽ từng công đoạn để đảm bảo rủi ro thấp nhất cho sản phẩm/ dịch vụ nào đó. Ngoài ra nhân viên QC sẽ bắt đầu từ khâu nhập nguyên liệu cho đến khi sản xuất ra sản phẩm đến tay người tiêu dùng cuối cùng. Công việc của nhân viên QC trong doanh nghiệp được thực hiện thường xuyên và liên tục, đòi hỏi họ phải chịu được nhiều áp lực. 

Trên đây là những chia sẻ về 7 công cụ QC vốn quen thuộc trong doanh nghiệp sản xuất. Nếu bạn đang tìm giải pháp để giúp quy trình kiểm soát được diễn ra tiết kiệm và khoa học, hãy tìm hiểu những công cụ QC được nêu trên để công việc trở nên dễ dàng hơn. 

Intern: Hồ Ngọc Bích

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

Xem thêm tuyển dụng việc làm IT hấp dẫn trên TopDev

Hướng dẫn cài đặt và cấu hình Nginx Amplify Agent trên Centos 7

nginx amplify agent
Hướng dẫn cài đặt và cấu hình Nginx Amplify Agent trên Centos 7

Bài viết được sự cho phép của tác giả Lê Chí Dũng

1. Chuẩn bị cài đặt Nginx Amplify Agent:

– Nginx chỉ hoạt động trên server chạy hệ điều hành Linux:

  • Ubuntu 12.04, 14.04, 16.04
  • Debian 7, 8
  • CentOS 6, 7
  • Red Hat 6, 7 (and systems based on it, e.g. Oracle Server)
  • Amazon Linux (latest release)
  • Gentoo Linux (experimental Ebuild)

– Hệ thống đã cài đặt Nginx từ version 1.10 trở lên

– NGINX Amplify Agent chỉ hoạt động  Python 2.6 và 2.7. Python 3 thì không hoạt động.

  App User Centricity: Làm sao tăng tỷ lệ duy trì lên 66%?
  Cài đặt ConfigServer Security and Firewall (CSF) và Webmin trên CentOS 7

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

2. Cài đặt và cấu hình Nginx Amplify Agent

1. Cài đặt

yum info nginx-amplify-agent

2. Cập nhật

yum update nginx-amplify-agent

3. Start service

systemctl start amplify-agent
# Restart service
systemctl restart amplify-agen

4. Gỡ cài đặt

yum remove nginx-amplify-agent

5. Kích hoat với API key

Bạn lấy mã cài đặt kích hoạt trên UI web Nginx Amplify Agent

Sau đó chạy đoạn code đó

# curl -sS -L -O \
https://github.com/nginxinc/nginx-amplify-agent/raw/master/packages/install.sh && \
API_KEY='ffeedd0102030405060708090a0b0c' sh ./install.sh

6. Kiểm tra Amplify Agent đã started

ps ax | grep -i 'amplify\-'

Cuối  cùng enjoy nhé! Cài đặt vô cùng đơn giản đúng không 😀

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

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

Xem thêm tuyển dụng các vị trí CNTT hấp dẫn trên TopDev