Khi tạo Entity trong Hibernate, chúng ta phải ánh xạ (mapping) các kiểu dữ liệu Java vào các kiểu dữ liệu trong database. Việc mapping này rất quan trọng, nó giúp Hibernate có thể chuyển đổi từ kiểu dữ liệu Java sang SQL và ngược lại một cách chính xác.
Trong bài này, tôi sẽ tổng hợp lại các kiểu dữ liệu tương ứng giữa Java, Hibernate và JDBC.
Bean, ApplicationContext, Spring Bean Life Cycle và Component scan
Bài viết được sự cho phép của tác giả Lê Chí Dũng
1. Bean là gì?
Trong documentation của Spring framework, thì bean được định nghĩa như sau:
In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container.
Nói một cách đơn giản, bean là những module chính của chương trình, được tạo ra và quản lý bởi Spring IoC container.
Các bean có thể phụ thuộc lẫn nhau, như ví dụ về Car, Engine và ChinaEngine từ đầu series tới giờ. Sự phụ thuộc này được mô tả cho IoC biết nhờ cơ chế Dependency injection.
Lúc này chỉ cần biết đơn giản nhất là dùng @Component lên class là class đó là một bean.
ApplicationContext là khái niệm Spring Boot dùng để chỉ Spring IoC container, tương tự như bean là đại diện cho các dependency.
Ngoài ra bạn có thể sẽ nghe nói về BeanFactory. Nó cũng đại loại như ApplicationContext, đại diện cho Spring IoC container nhưng ở mức cơ bản. ApplicationContext thì ở mức cao hơn, cung cấp nhiều tính năng hơn BeanFactory như i18n, resolving messages, publishing events,…
Khi ứng dụng Spring chạy, Spring IoC container sẽ quét toàn bộ packages, tìm ra các bean và đưa vào ApplicationContext. Cơ chế đó là Component scan.
Cách lấy bean ra từ Context
Tất nhiên trước khi lấy bean ra từ context thì phải có context rồi. Câu hỏi đặt ra là biến context ở đâu?
Đó là ngay dòng bắt đầu chương trình Spring Boot. Câu lệnh sau.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Dòng method SpringApplication.run() sẽ return về một object ApplicationContext interface, đại diện cho IoC container.
Chúng ta có thể lấy ra bean từ đây, dùng method getBean().
// Lấy ra bean có class cụ thể
Car car = context.getBean(Car.class);
// Lấy ra theo tên và class
// Tuy là Engine.class nhưng Engine lại là interface
Engine engine = context.getBean("ChinaEngine", Engine.class);
3. Kĩ thuật inject bean vào bean khác
Ví dụ bạn có hai bean là Car và Engine (như ví dụ từ đầu series tới giờ). Và Car thì phụ thuộc vào Engine, do đó theo Dependency injection thì chúng ta cần inject Engine vào trong Car.
3.1. Sử dụng @Autowired
Chúng ta sử dụng annotation @Autowired để báo cho Spring biết tự động tìm và inject bean phù hợp vào vị trí đặt annotation. Ví dụ.
// Annotation chỉ đánh dấu lên class
public interface Engine {
void run();
}
@Component
public class ChinaEngine implements Engine {
@Override
public void run() {}
}
@Component
public class Car {
// Báo cho Spring tìm bean nào phù hợp với Engine interface
// Và có một bean phù hợp là ChinaEngine
// Nó tương đương với = new ChinaEngine()
@Autowired
private final Engine engine;
}
Cách dùng @Autowired trên field là không được khuyến khích, do nó sử dụng Java reflection để inject. Chúng ta nên cân nhắc đổi qua dùng inject theo kiểu constructor hoặc setter.
3.2. Inject qua constructor hoặc setter
Code inject theo kiểu constructor-based nên dùng khi các module là bắt buộc. Khi đó Spring Boot khi tạo bean (cũng chỉ là tạo object, gọi constructor thôi) thì sẽ đưa các phụ thuộc vào constructor khi gọi.
Ví dụ class Car đã được sửa lại để inject Engine vào qua constructor.
@Component
public class Car {
private final Engine engine;
// Các bản Spring Boot mới thì không cần @Autowired trên constructor
public Car(Engine engine) {
this.engine = engine;
}
}
Hoặc dùng kiểu setter-based như sau. Spring Boot sau khi tạo xong bean Car sẽ gọi thêm method setEngine() sau đó.
@Component
public class Car {
private final Engine engine;
// Thêm @Required để setter luôn được gọi để inject
@Required
public void setEngine(Engine engine) {
this.engine = engine;
}
}
Cách dùng setter để inject thường dùng trong trường hợp phụ thuộc vòng, module A phụ thuộc vào B và ngược lại. Do đó, nếu cả hai đều sử dụng constructor based injection thì Spring Boot sẽ không biết nên tạo bean nào trước. Vì thế, giải pháp là một bean sẽ dùng constructor, một bean dùng setter như trên.
4. Khi Spring Boot không biết chọn bean nào?
4.1. Khi tìm thấy nhiều bean phù hợp
Cũng lấy ví dụ trên, nếu chúng ta tạo thêm class VNEngine có chức năng tương tự ChinaEngine.
@Component
public class VNEngine implements Engine {
@Override
public void run() {}
}
Thì Spring Boot sẽ báo lỗi như sau (báo khi chạy và cả trong IDE nữa.
Có thể hiểu do Spring Boot đã tìm thấy hai bean phù hợp để inject vào Car. Do cả hai VNEngine và ChinaEngine đều implements Engine, mà Car cần Engine nên không biết nên chọn cái nào.
4.2. Giải pháp
Có hai cách giải quyết vấn đề này. Thứ nhất là dùng @Primary đánh dấu lên một bean. Khi đó bean này sẽ được ưu tiên chọn hơn, trong trường hợp có nhiều bean phù hợp trong context.
@Component
@Primary
public class VNEngine implements Engine {
...
}
Cách 2 là chỉ định rõ tên bean (tên class) cụ thể được inject bằng @Qualifier.
@Component
public class Car {
@Autowired
@Qualifier("VNEngine") // Phải khớp hoa thường luôn nhe
private final Engine engine;
}
Đối với constructor hay setter based cũng tương tự, chỉ cần có @Qualifier trước tên field cần inject vào là được.
3. Spring Bean Life Cycle
1.1. Bean life cycle
Trong bài trước chúng ta đã tìm hiểu sơ lược về bean là gì, hôm nay chúng ta sẽ đi sâu hơn tí nhé.
Vòng đời (life cycle) của bean được hiểu là từ khi bean được tạo ra cho tới khi chết đi, sẽ có những sự kiện (event) khác nhau xảy ra. Về vòng đời của bean có thể mô tả bởi sơ đồ sau.
Nhìn có vẻ dài và khó hiểu, nhưng đại loại sẽ gồm các bước sau:
IoC container tạo bean bằng cách gọi constructor (có thể inject các bean dependency vào đây)
Gọi các setter method để inject các bean vào bằng setter based injection
Các method khởi tạo khác được gọi (không cần quan tâm nhiều)
@PostConstructor được gọi
Init method được gọi
Sau đó bean sẽ sẵn sàng hoạt động. Nếu sau đó bean không dùng nữa thì nó sẽ được hủy:
Gọi @PreDestroy
Hủy bean như các object thông thường
1.2. @PostConstructor và @PreDestroy
Đây là hai event khá quan trọng với bean, bạn có thể hook một method vào đó để thực thi khi event xảy ra:
@PostConstruct là sau khi bean đã khởi tạo xong
@PreDestroy là trước khi bean bị phá hủy
Chúng ta dùng hai annotation trên đánh dấu lên method nào đó, method đó sẽ được tự động gọi khi sự kiện bean xảy ra.
class Car {
@Autowired
private final Engine engine;
@PostConstruct
public void testRun() {
engine.run();
engine.stop();
}
@PreDestroy
public void stopEngine() {
engine.stop();
}
}
Như code ví dụ trên, mình gắn @PostConstruct cho method testRun(). Method này được gọi khi bean Car được tạo ra và khởi tạo hoàn chỉnh. Và trước khi Car bị phá hủy, thì cần gọi stopEngine tương tự như trên.
Dùng trong thực tế thì hai annotation trên làm các nhiệm vụ như:
@PostConstruct dùng để thực hiện một số task khi khởi tạo bean
@PreDestroy thực hiện các task để dọn dẹp bean sau khi dùng xong
2. Các loại bean
Nói đúng hơn thì gọi là các scope, phân loại dựa trên số lượng bean được tạo ra. Bean gồm có 5 scope:
Singleton (mặc định): IoC container chỉ tạo đúng duy nhất 1 object từ class bean này
Prototype: return một bean object riêng biệt cho mỗi lần sử dụng.
Request: tạo mỗi bean cho mỗi request
Session: tạo mỗi bean cho mỗi session
Global session: tạo mỗi bean cho mỗi global session (cái này không hiểu lắm)
Trong 5 scope trên chúng ta chỉ quan tâm tới hai scope đầu. Thường thì các bạn sẽ ít đụng tới prototype bean, nhưng mình cũng viết ra tại đây luôn.
Đối với singleton bean thì khỏi cần đánh dấu gì hết, nó là mặc định rồi. Còn nếu muốn chỉ định một class là prototype bean thì dùng @Scope như sau.
@Component
@Scope("prototype")
class PrototypeBean {
...
}
Nói rõ hơn về prototype bean, ví dụ bean X được sử dụng bởi hai bean khác là A, B:
Nếu X là singleton bean, thì chỉ có một object X được tạo ra. A và B dùng chung X.
Nếu X là prototype bean, thì có 2 X được tạo ra cho 2 bean khác sử dụng là X cho A và X cho B.
3. Cách định nghĩa bean
Có 3 cách định nghĩa class là một bean:
Khai báo trong file XML
Dùng annotation trên class
Dùng @Configuration và @Bean
Tùy từng trường hợp cụ thể mà dùng cho phù hợp. Ví dụ trong series này mình không bàn sâu về cấu hình bean bằng XML (do Spring Boot sinh ra không phải để cấu hình).
3.1. Dùng XML, annotations
Nhưng đơn giản, các bạn cũng nên biết trước đây Spring dùng XML để cấu hình các bean như sau. Nó khá là cực nên người ta dùng cách khác hay hơn.
<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Đây là bean Car -->
<bean id="" class="Car" init-method="testRun">
<!-- Cấu hình thuộc tính property cho bean -->
</bean>
</beans>
Do đó người ta mới dùng cách cấu hình bean dựa trên các annotation như @Component. Cụ thể thì như bài trước có nói, chỉ cần đánh dấu @Component lên trên class thì IoC sẽ biết và tạo bean từ class đó.
@Component
public class Car {
...
}
Ngoài ra có các annotations khác cụ thể hơn như @Service, @Repository, @Controller,… cũng bao gồm @Component, nên tác dụng của chúng cũng là tạo bean.
3.3. Dùng @Bean bên trong @Configuration
Cách này dùng cho trường hợp bean cần thực hiện nhiều thao tác phức tạp để khởi tạo, hoặc có nhiều bean liên quan với nhau. Do đó, thay vì khởi tạo riêng rẽ từng class là từng bean, thì gom chung các bean cần khởi tạo lại bỏ vào class chứa là @Configuration.
Thường thì các class đánh dấu @Configuration có hậu tố là Config.
@Configuration
public class AppConfig {
// Khởi tạo trước các logic phức tạp
// Có thể quy định thứ tự khởi tạo bean bằng `@Order`
public AppConfig() {
...
}
@Bean
public Car carBean() {
return new Car();
}
@Bean
public PasswordEncoder passwordEncoderBean() {
return new BCryptPasswordEncoder();
}
// Có thể định nghĩa nhiều bean khác với @Bean
}
Khi Spring tìm thấy class @Configuration, nó sẽ tạo bean của class này trước (do @Configuration cũng là @Component). Trong khi tạo thì các logic khởi tạo cũng được thực thi, để chuẩn bị sẵn sàng tạo các @Bean bên trong.
Sau đó Spring Boot sẽ tìm các method được đánh dấu @Bean bên trong @Configuration để tạo bean. Thường thì các bean dạng này ngắn và return ngay object chứ không phải để Spring Boot tạo ra.
Các bean cũng được đưa vào ApplicationContext như bình thường.
Tuy nhiên, không phải class nào đánh dấu cũng được tạo bean. Mà phải có điều kiện quá trình component scan của IoC phải tìm thấy nó. Chúng ta sẽ đi tiếp về component scan ngay sau đây.
4. Component scan
4.1. Cách component scan hoạt động
Khi ứng dụng Spring Boot bắt đầu chạy, thì nó sẽ tìm hết các class đánh dấu là bean trong chương trình và tạo bean. Quá trình tìm kiếm các bean này gọi là component scan.
Component scan sẽ tìm toàn bộ class ở package cùng cấp hoặc các package thấp hơn
Do đó, class đánh dấu @SpringBootApplication có chứa main method sẽ là nơi bắt đầu. Spring Boot sẽ tìm từ package này (package gốc) tìm xuống để tạo các bean.
Do cấu trúc thư mục mặc định của Spring Boot nó thế, nên từ package gốc có DemoApplication.java là com.tonghoangvu.demo, nó sẽ tìm:
Các class cùng cấp, tìm được DemoApplication class, tạo bean
Tìm xuống các package thấp hơn như com.tonghoangvu.demo.components và com.tonghoangvu.demo.controllers, tìm thêm được các class như ChinaEngine, Car, UserController (Engine.java là interface nhé).
Do đó, mặc định mọi class được khai báo là bean đều có thể được tìm được.
4.2. Tùy chỉnh package tìm kiếm
Trong trường hợp bạn chỉ muốn Spring Boot tìm các bean trong một package cụ thể, ví dụ chỉ tìm trong thư mục components thì có 2 cách như sau.
// Cách 1 dùng @ComponentScan với 1 hoặc nhiều string (cần có {})
@ComponentScan("com.tonghoangvu.demo.components")
// Cách 2 thêm thuộc tính @SpringBootApplication scanBasePackages
@SpringBootApplication(scanBasePackages = {
"com.tonghoangvu.demo.components",
"com.tonghoangvu.demo.controllers"
})
public class DemoApplication {
public static void main(String[] args) {
...
}
}
Bài viết hôm nay đến đây là xong, cũng coi như là đi gần hết phần lý thuyết của Spring Boot rồi.
Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Redis là một open-source cho phép chúng ta có thể lưu trữ data trong memory. Chúng ta có thể sử dụng Redis để làm database, caching hoặc message broker. Trong bài viết này, mình hướng dẫn các bạn cách cài đặt Redis sử dụng Docker các bạn nhé!
Đầu tiên, các bạn có thể đi đến trang official Docker Image của Redis tại https://hub.docker.com/_/redis để kiểm tra version mới nhất của Redis Image. Sau đó thì sử dụng command docker run để cài đặt Redis như sau:
docker run -p 6379:6379 -d redis
Ở đây, mình đang sử dụng latest version của Redis, mình cũng expose port chạy mặc định của Redis là 6379 ra bên ngoài.
Mô Tả Công Việc IT HelpDesk & Những Điều Cần Biết Với Vị Trí Này
Ngành Công nghệ thông tin đang ngày càng phát triển và dẫn đến sự ra đời của rất nhiều các vị trí công việc khác nhau. Trong số đó, IT Helpdesk được đánh giá là một phần quan trọng và không thể thiếu cho một sản phẩm công nghệ hoàn hảo. Vậy IT Helpdesk là gì, mô tả công việc IT Helpdesk này ra sao, cần những kỹ năng gì để làm tốt công việc? Cùng TopDev tìm hiểu thêm với bài viết dưới đây nhé!
Mô tả công việc IT Helpdesk
IT Helpdesk là gì?
IT Helpdesk, như ngay từ tên vị trí đã đề cập, công việc này sẽ gắn liền với việc hỗ trợ các vấn đề phát sinh trong ngành công nghệ thông tin. Cụ thể, các nhân viên IT Helpdesk sẽ là người nghiên cứu và đưa ra các giải pháp tư vấn để khắc phục các sự cố liên quan đến mạng máy tính cũng như các thiết bị công nghệ có liên quan.
Vì có vai trò rất quan trọng trong quá trình xử lý sự cố liên quan đến IT nên các IT Helpdesk đều là những người có “tay nghề” khá vững vàng. Trong nhiều trường hợp cần thiết, các chuyên gia IT Helpdesk là người đầu tiên tiếp xúc với khách hàng cũng như hướng dẫn họ xử lý sự cố qua điện thoại, tin nhắn hay email.
Tùy vào vị trí cụ thể với những vai trò khác nhau mà mỗi IT Helpdesk ở mỗi công ty sẽ có sự khác biệt nhất định. Tuy nhiên, về cơ bản thì mô tả công việc IT Helpdesk sẽ bao gồm:
Duy trì chất lượng, đảm bảo hệ thống thông tin được hoạt động ổn định.
Kịp thời phát hiện và xử lý các vấn đề liên quan đến sự cố máy tính.
Theo dõi và tư vấn nâng cấp cho hệ thống mạng thông tin nội bộ trong trường hợp cần thiết.
Bảo trì hệ thống mạng và máy tính của công ty.
Chịu trách nhiệm chăm sóc khách hàng thông qua điện thoại, email hoặc gặp mặt trực tiếp về các vấn đề liên quan đến cài đặt phần mềm.
Sắp xếp, hệ thống hóa và quản lý dữ liệu người dùng.
Thử nghiệm và đánh giá những công nghệ mới phục vụ cho công việc của công ty.
Sở hữu các bằng cấp liên quan đến khoa học máy tính, công nghệ thông tin, các chứng chỉ về máy tính là điều cần có ở một IT Helpdesk. Bên cạnh đấy, một IT helpdesk không chỉ cần giỏi kiến thức chuyên môn từ khi bắt đầu mà còn phải liên tục cập nhật thêm các thông tin mới liên quan đến ngành nghề của mình. Vì công nghệ luôn được xem là mảnh đất màu mỡ cho những phát minh mới nên các sản phẩm mới luôn ra đời rất nhanh và nhiều, nếu không tự chủ trong việc tìm hiểu kiến thức mới sẽ khiến bạn trở nên tụt hậu.
Kỹ năng giao tiếp được đánh giá là yếu tố cần thiết với các nhân viên trong vai trò là IT Helpdesk. Trong quá trình làm việc với khách hàng, việc giao tiếp khéo léo và xử lý tốt thông tin chắc chắn sẽ rất cần thiết. Bạn không chỉ giải quyết được những khó khăn của khách hàng mà còn có thể giải thích và khắc phục vấn đề cho khách hàng một cách đơn giản và dễ hiểu nhất.
Bên cạnh đó, sự kiên nhẫn và tập trung cũng giúp các IT Helpdesk hoàn thành công việc của mình tốt hơn. Vì đây là công việc đòi hỏi độ chính xác cao nên bất cứ sai sót nào đều không được cho phép. Kiên nhẫn với thời gian và tập trung cao độ là bí quyết để thành công trong việc khắc phục sai sót.
Ngoài ra, khả năng xử lý các tình huống khẩn cấp chắc chắn sẽ là điểm cộng cực lớn với các chuyên gia IT Helpdesk. Bất cứ lúc nào khi có vấn đề đột xuất xảy ra, IT Helpdesk sẽ phải là người bình tĩnh và tìm hiểu rõ nguyên nhân vấn đề để có hướng khắc phục tốt nhất.
Như nhiều công việc khác trong lĩnh vực IT, IT Helpdesk có mức lương khá cao so với mặt bằng chung. Theo đó, mức lương của IT Helpdesk hiện nay dao động trên mức 11 triệu đồng/tháng. Hi vọng với bài viết này, người đọc sẽ phần nào hiểu thêm về công việc IT Helpdesk và có được định hướng công việc tốt hơn cho mình. Đón đọc thêm nhiều bài viết hấp dẫn khác tại TopDev nhé!
Cách sử dụng Pocket để lưu lại tất cả những liên kết hữu ích
Bài viết được sự cho phép của blogchiasekienthuc.com
Trong quá trình lướt web, đọc báo hay là đọc các bài viết trên blog thì chắc chắn sẽ có lúc bạn bắt gặp những bài viết có nội dung rất hay và sâu sắc, bạn muốn lưu lại những bài viết để đến khi nào có thời gian thì đọc.
Vậy bạn sẽ lưu lại bài viết đó như thế nào?
Vâng, mặc định thì trên smartphone của chúng ta cũng đã có sẵn tính năng lưu lại bài viết vào danh sách đọc rồi. Tuy nhiên, chúng khá là phân tán và chỉ có thể xem lại được trên chính thiết bị mà bạn đã bookmark mà thôi.
Còn đối với trình duyệt web trên máy tính thì bạn thường sử dụng tính năng Bookmark để lưu lại các liên kết hữu ích đúng không? Nói chung là cách này cũng được, nhưng chưa thực sự được tối ưu lắm.
Vậy cách tối ưu nhất là gì?
Vâng, đó là cách đồng bộ chúng vào chung một tài khoản để đọc được trên mọi thiết bị. Có nghĩa là khi bạn lưu đường link của một bài viết khi bạn truy cập trên chiếc điện thoại A, thì khi sử dụng chiếc điện thoại B, hay chiếc máy tính C… thì bạn vẫn có thể xem được liên kết đã lưu trên chiếc điện thoại A đó.
Vậy có tiện ích nào có thể làm được điều này không?
Có đấy, trong bài viết này mình sẽ giới thiệu cho các bạn một ứng dụng vô cùng tiện ích có tên là Pocket: Save. Read. Grow để giải quyết những vấn đề liên quan đến việc lưu các bài viết trên mạng nhé.
Chính vì thế mà có thể nhiều bạn sẽ chỉ đọc lướt qua, mà chưa biết nó thực sự hữu ích như thế nào. Vậy nên chúng ta sẽ cùng nhau tìm hiểu kỹ hơn trong bài viết này nhé.
#1. Pocket: Save. Read. Grow là gì? Và tại sao bạn nên sử dụng?
Dành cho những ai chưa biết thì Pocket: Save. Read. Grow là một ứng dụng miễn phí dành riêng cho những dân đam mê đọc sách và tìm hiểu thông tin, hỗ trợ trên đa nền tảng (Google Play, AppStore, Amazon, tiện ích trên Google Chrome…)
Cá nhân mình thấy đây là một ứng dụng vô cùng hữu ích, giúp bạn tổng hợp và lưu lại đường link của mọi bài viết, mọi video trên các web mà bạn muốn và bạn hoàn toàn có thể xem lại bất cứ khi nào cần đến.
Ngoài những tính năng mà mình vừa mới kể ở trên ra thì Pocket: Save. Read. Grow có một ưu điểm đặc biệt mà ít tiện ích nào có đó là:
Những đường link mà bạn đã lưu bằng Pocket thì ngay cả khi thiết bị đó không có kết nối Internet, bạn vẫn có thể xem được nội dung. Một tính năng quá hữu ích !
#2. Cách tải và sử dụng Pocket: Save. Read. Grow
Link tải đã có đầy đủ trên trang chủ tại địa chỉ: https://getpocket.com/add
Ví dụ, để tải được ứng dụng Pocket này về điện thoại Android, các bạn hãy làm từng bước của mình như sau:
+ Bước 1: Mở chiếc điện thoại của mình ra, truy cập vào kho ứng dụng CH Play/ Google Play.
+ Bước 2: Bạn hãy cài đặt ứng dụng Pocket thông qua đường link bên trên hoặc là tìm kiếm với từ khóa Pocket: Save. Read. Grow trong khung tìm kiếm và cài đặt ứng dụng này.
+ Bước 3: Sau khi tải và cài đặt ứng dụng Pocket: Save. Read. Grow thì việc đầu tiên là bạn cần làm là tạo một tài khoản để sử dụng ứng dụng này.
Ở đây thì mình sẽ sử dụng tài khoản Gmail trên Google luôn cho tiện, đỡ tốn công lập cái mới.
Tuy nhiên, nếu bạn muốn lập tài khoản riêng cho Pocket thì cũng không có vấn đề gì cả, bởi các bước để tạo tài khoản Pocket cũng rất nhanh và đơn giản. Để dễ hình dung hơn thì các bạn hãy nhìn vào hình bên trên, mình đã giải thích rất cụ thể.
+ Bước 4: Sau khi đã truy cập bằng tài khoản mới tạo thì Pocket: Save. Read. Grow sẽ hiển thị những trang giới thiệu tính năng để bạn xác nhận.
Các bạn cứ bấm hết vào ô màu xanh thôi, còn trang thứ hai thì các bạn có thể bấm vào phần Skip cũng được.
+ Bước 5: Okay, việc cài đặt đã hoàn tất, bây giờ thì bạn có thể sử dụng ứng dụng này được ngay rồi.
#3. Cách sử dụng ứng dụng Pocket: Save. Read. Grow
Sau khi hoàn tất việc cài đặt, bây giờ mình sẽ hướng dẫn cho các bạn cách để lưu một bài viết hay một video bất kỳ bằng Pocket: Save. Read. Grow.
+ Bước 1: Đầu tiên bạn hãy mở một bài viết bất kỳ mà bạn thích, ở đây thì mình sẽ lấy ví dụ bằng bài viết trên blogchiasekienthuc.com nhé.
+ Bước 2: Hãy mở bài viết mà bạn muốn lưu => tìm đến phần Chia sẻ => và nhấn vào nó.
+ Bước 3: Sau khi bấm vào phần chia sẻ thì các bạn tiếp tục bấm vào Add to Pocket
Còn đối với iPhone thì bạn làm như sau (trình duyệt Safari): Bạn nhấn vào nút Chia sẻ ở bên dưới.
Sau đó kéo xuống, chọn Save to Pocket là xong.
+ Bước 4: Như vậy là bạn đã lưu lại bài viết này vào trong ứng dụng Pocket thành công rồi đấy.
Ngoài ra, nếu bạn muốn áp dụng với video thì cũng hoàn toàn tương tự, không có gì thay đổi hết.
+ Bước 5: Để xem lại các liên kết đã lưu này thì bạn hãy mở ứng dụng Pocket ngoài màn hình điện thoại ra để đọc. Tất cả các đường link liên kết sẽ nằm trong đấy. Bạn có thể đọc lại bất cứ lúc nào mà bạn muốn.
#4. Làm thế nào để đồng bộ Pocket giữa các thiết bị?
Đây là vấn đề mà mình đã vạch ra ở đầu bài viết, để đồng bộ ứng dụng Pocket giữa các thiết bị thì bạn chỉ việc cài đặt Pocket lên những thiết bị mà bạn muốn sử dụng => sau đó đăng nhập bằng tài khoảng Pocket là xong.
Nói dễ hiểu hơn là bạn sử dụng một tài khoản Pocket chung cho tất cả các thiết bị, như vậy thì dữ liệu sẽ tự động được đồng bộ với nhau. Đơn giản vậy thôi 🙂
#5. Lời kết
Vâng, như vậy là mình đã hướng dẫn xong cho các bạn cách sử dụng Pocket để lưu lại các bài viết hữu ích rồi nhé.
Cá nhân mình thấy đây là một ứng dụng rất tuyệt vời, nó giúp cho quá trình tích lũy tri thức của chúng ta được hiệu quả hơn, đẽ dàng hơn và nhanh chóng hơn.
Như thường lệ, nếu thấy bài viết này hay thì đừng quên like, chia sẻ cho bạn bè, người thân và đừng quên ghé thăm Blog Chia Sẻ Kiến Thức mỗi ngày để đón đọc những thông tin vô cùng hữu ích nhé.
Hiển thị sản phẩm theo danh mục dạng tabs trong woocommerce
Bài viết được sự cho phép của tác giả Võ Quang Huy
Hôm nay mình sẽ hướng dẫn cho các bạn một chức năng rất hay gặp trong quá trình học lập trình theme wordpress woocommerce. Đó là chức năng hiển thị sản phẩm theo danh mục dạng tabs.
Có nghĩa là khi click vào các link tabs thì phía dưới sẽ xuất hiện các content tương ứng. Các bạn chú ý khi click vào link có href=”#menu1″ thì content ở tabs có id là id=”menu1″ sẽ hiện
Ráp code wordpress hiển thị sản phẩm theo danh mục dạng tabs
Hiển thị danh mục sản phẩm (các tabs)
Để lấy danh mục sản phẩm chúng ta có đoạn code sau:
Ở nội dung tabs có id là id=”home” mình sẽ get ra 8 sản phẩm mới nhất tương ứng với tabs tất cả. Sản phẩm ở vị trí này sẽ show tất cả không biệt tabs nào của danh mục nào.
Ở nội dung các tabs khác, ban đầu chúng ta sẽ chạy vòng lặp get danh mục, trong mỗi danh mục được hiển thị chúng ta lại tiếp tục chạy vòng lặp get bài viết với product_cat tương ứng bằng với slug của danh mục.
Các điểm chú ý
Nội dung tabs (Tất cả) id=”home” sẽ hiển thị đầu tiên có gán class “active”
Các nội dung các tabs tiếp theo có id chính bằng slug của danh mục id=”<?php echo $cate->slug; ?>”
Trong vòng lặp get post chúng ta có một thông số đầu vào là ‘product_cat’ => $cate->slug đây chính là điều kiện hiển thị sản phẩm theo danh mục
Hôm nay mình đã hướng dẫn cho các bạn cách để làm tính năng hiển thị sản phẩm theo danh mục dạng tabs. Bài viết trong khá dài nhưng thật sự nếu bạn nắm các phần về frontend thì cũng không có chi khó cả.
Ưu điểm của việc bố trí sản phẩm theo tabs
Giao diện đẹp
Thể hiện được nhiều nội dung ra 1 page
Tăng khải nghiệm của người dùng
Nhược điểm
Nặng website (Ví dụ danh mục của bản có nhiều việc hiển thị như thế này sẽ show rất nhiều dữ liệu ra 1 page -> Nặng page)
Khó khăn trong việc phân trang
Hy vọng bài viết này sẽ giúp ích cho các bạn khi làm dự án cũng như là học làm theme wordpress.
Với sự phát triển mạnh mẽ của công nghệ thông tin (CNTT) mà cụ thể mà công nghệ phần mềm (CNPM), cuộc cách mạng đó đã tạo ra một khối lượng khổng lồ các phần mềm ở nhất nhiều lĩnh vực khác nhau.
Việc sử dụng thành thạo và nắm bắt được tất cả các vấn đề mà một phần mềm hỗ trợ đã là rất khó đối với nhiều người sử dụng thế nên việc tạo ra phần mềm đó còn khó hơn gấp nhiều lần. Mà chỉ có niềm đam mê lập trình, tư duy sáng tạo, tư duy logic, ham học hỏi và kinh nghiệm cuộc sống mới có thể theo nghiệp lập trình viên được, ở đây chúng ta quan niệm rằng nếu hội tụ các yếu tố trên thì sẽ cho ra sản phẩm phần mềm tốt.
Bạn sẽ rất dễ nản lòng khi mà cả ngày mới code xong một chức năng, khi mà cả ngày mới tìm ra được lỗi. Niềm vui có lẽ sẽ rất khó tả khi bạn giải quyết được vấn đề đó. Rồi một ngày, bạn gặp lỗi tương tự, bạn sửa giống như những lần trước mà tại sao nó vẫn không chạy? Rồi bạn lại mất một ngày, hai ngày thậm chí hai ngày rưỡi để tìm ra được lỗi đó là do đâu. Khi đó thì kim đồng hồ đã chỉ 2-3h sáng nhưng bạn vẫn cảm thấy thích thú và tiếp tục khám phá thế giới lập trình.
Có một điều rất thú vị rằng dù tìm ra được lỗi hay không tìm ra được lỗi thì bạn vẫn không muốn dừng lại ở đó để đi ngủ mà vẫn tiếp tục ngồi code. Khi bạn chưa tìm ra lỗi thì bạn rất mong muốn phải tìm ngay ra bằng được lỗi này và như thế lại tiếp tục và khi bạn đã tìm ra lỗi rồi thì bạn lại muốn phát triển thêm hơn nữa.
Có rất nhiều hướng đi cho một lập trình viên, ở đây tôi bàn tới hướng đi lập trình website bằng ngôn ngữ PHP sử dụng cơ sở dữ liệu MySQL. Vậy để phát triển ứng dụng web bằng công nghệ trên với người bắt đầu các bạn cần phải chuẩn bị những gì? Chúng ta sẽ xem xét như dưới đây.
Các công cụ cần thiết khi lập trình với PHP &MySQL
Có rất nhiều công cụ, tuy nhiên các bạn có thể tham khảo các công cụ mà tác giả đã và đang sử dụng:
Một máy tính? Đây là điều bắt buộc rồi phải không các bạn.
Một webserver ảo (XAMPP): đây là điều nên làm trước khi chúng ra triển khai sản phẩm trên hệ thống thật vì nó không tốn kém chi phí, chủ động hơn trong quản lý nhưng đổi lại môi trường của nó có thể sẽ khác vài chỗ so với hệ thống thật.
Một IDE mạnh mẽ? Đây hoàn toàn là do thói quen sử dụng tuy nhiên tác giả khuyên các bạn nên sử dụng PHPStorm để viết mã nguồn vì công cụ này hỗ trợ viết code rất tốt do tính năng gợi nhớ thư viện, kiểm tra cú pháp, liên kết trực tiếp với server thật để upload file lên host, tính năng tìm kiếm, thay thế, mở thư mục… cũng rất tiện lợi và mạnh mẽ.
Một phần mềm thiết kế DB với độ trực quan để phân tích và báo cáo rất cao là MySQL Workbench. Nó cho phép bạn kéo thả để thiết kế các bảng dữ liệu, các mối quan hệ giữa các bảng, quản lý việc tạo khóa chính, sinh khóa ngoại rất tiện lợi.
Một phần mềm thao tác truy vấn với cơ sở dữ liệu. Thực ra khi bạn cài đặt XAMPP thì nó đã tích hợp sẵn hệ quản trị cơ sở dữ liệu phpMyAdmin. Tuy nhiên, phần mềm phpMyAdmin có nhiều hạn chế khi thao tác và thiết kế DB nên 2 tính năng trên được khắc phục bởi SQLYog và MySQL Workbench.
Chi tiết các tính năng cụ thể các bạn có thể truy cập vào trang chủ của nó để tìm hiểu thêm. Đến đây tác giả xin được dừng lại ở đây và chúng ta sẽ tìm hiểu các tính năng tiện ích của chúng trong loạt bài viết khác.
Hibernate sử dụng các Annotation để mô tả các thông tin cho một Entity. Chúng ta có thể sử dụng các Annotation nằm trong package javax.persistence của Java Persistence API hoặc sử dụng các annotation trong API của hibernate nằm trong package org.hibernate.annotations. Tuy nhiên, tôi khuyến khích các bạn sử dụng các Annotation của Java Persistence API bởi vì sau này chúng ta muốn chuyển sang một ORM khác sẽ dễ dàng hơn mà không phải thay đổi code.
Trong bài này, tôi sẽ hướng dẫn các Annotation thông dụng nhất của Java Persistence API để mô tả thông tin cho một Entity.
@Entity được sử dụng để chú thích một class là một Entity.
Thuộc tính name của @Entity là không bắt buộc. Việc chỉ định rõ name của @Entity cho phép viết ngắn câu HSQL.
Entity khớp với một bảng lấy theo tên theo thứ tự ưu tiên:
name trong @Table.
name trong @Entity.
name của class.
@Table
Một table trong database có thể có nhiều ràng buộc unique (duy nhất). Chúng ta có thể sử dụng @Table để mô tả các ràng buộc này.
@Table cho phép chú thích tên bảng thông qua thuộc tính name (thuộc tính này không bắt buộc).
Nếu không chỉ rõ tên bảng trong phần tử name, Hibernate sẽ dựa vào phần tử name của @Entity sau đó mới tới tên của class.
@Column
@Column được sử dụng để chỉ định thông tin chi tiết của cột mà một field của entity sẽ được ánh xạ với một column trong database.
Thuộc tính name được sử dụng để chị định tên cột nào trong database map với tên field được chú thích. Nếu không chỉ định, Hibernate sẽ lấy tên field map với tên cột trong database.
Thuộc tính length cho phép kích thước của cột. @Column không chỉ rõ phần tử length, mặc định nó là 255.
Thuộc tính nullable cho phép cột được đánh dấu KHÔNG NULL khi schema được tạo ra. Giá trị nullable mặc định là true.
Thuộc tính unique cho phép cột được đánh dấu chỉ chứa các giá trị duy nhất.
Chúng ta có thể không cần chỉ định @Column cho tất cả các field nếu tên field và tên column và tên trong database là giống nhau.
@Transient
Trong một số trường hợp, trong entity class có chứa một field mà field này không tồn tồn tại trong database. Khi đó chúng ta sẽ gặp lỗi “java.sql.SQLSyntaxErrorException: Unknown column ‘additionalPropery’ in ‘field list’”.
Để tránh lỗi này, chúng ta có thể sử dụng @Transient để thông báo rằng thuộc tính/ phương thức này không liên quan gì tới một cột nào dưới database. Khi đó, Hibernate sẽ bỏ qua field này.
@Temporal
@Temporal sử dụng để chú thích cho cột dữ liệu ngày tháng và thời gian (date time).
Có 3 giá trị cho TemporalType:
TemporalType.DATE : chú thích cột sẽ lưu trữ ngày tháng năm (bỏ đi thời gian).
TemporalType.TIME : chú thích cột sẽ lưu trữ thời gian (Giờ phút giây).
TemporalType.TIMESTAMP : chú thích cột sẽ lưu trữ ngày tháng và cả thời gian.
@Id
@Id được sử dụng để mô tả đây là Id (Identity) của Entity, nó tương đương với cột đó là khóa chính (Primary Key) của table trong database.
Khóa chính có thể là một trường duy nhất hoặc kết hợp nhiều trường tùy thuộc vào cấu trúc bảng trong database.
@GeneratedValue được sử dụng để Hibernate tự động tạo ra giá trị và gán vào cho một cột trong trường hợp insert mới một Entity vào database. Nó có thể gắn trên cột Id hoặc một cột nào đó.
Annotation này cũng được sử dụng cùng với @Generator.
Theo mặc định, chú thích @Id sẽ tự động xác định chiến lược tạo primary key, nhưng có thể ghi đè bằng cách áp dụng chú thích @GeneratedValue có hai tham số strategy và generator.
GenerationType.AUTO
Column được đánh dấu bởi @GeneratedValue(strategy= AUTO) sẽ được gán giá trị tự động, giá trị đó có thể được sinh ra bởi SEQUENCE hoặc tự tăng (Nếu cột này có kiểu IDENTITY). Nó phụ thuộc vào loại database.
Với Oracle, PostgreSQL, Hibernate nó sẽ gọi một Sequence có tên Hibernate_Sequence để tạo ra một giá trị tăng dần để gán giá trị cho cột này. Với các DB khác chẳng hạn như MySQL, DB2, SQL Server, Sysbase cột có thể là kiểu IDENTITY và giá trị của nó có thể tự tăng.
GenerationType.IDENTITY
Cột có kiểu IDENTITY chỉ được hỗ trợ bởi một vài loại cơ sở dữ liệu, không phải là tất cả, ví dụ MySQL, DB2, SQL Server, Sybase và PostgreSQL. Oracle không hỗ trợ cột kiểu này.
GenerationType.SEQUENCE
SEQUENCE là một đối tượng trong cơ sở dữ liệu, lưu trữ một giá trị tăng dần sau mỗi lần gọi nó để lấy giá trị tiếp theo, và được hỗ trợ bởi Oracle, DB2, và Postgres.
GenerationType.TABLE
Khi sử dụng GenerationType.TABLE , chúng ta cần định nghĩa một table hibernate_sequences như sau:
Ta có bảng Category sử dụng GenerationType.TABLE như sau:
@Data
@Entity
@Table
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
@Column
private String name;
}
Hibernate cho phép chúng ta tạo Id table dựa trên org.hibernate.id.enhified.TableGenerator xác định một bảng có thể chứa nhiều giá trị được đặt tên cho bất kỳ Entity nào.
Chẳng hạn, chúng ta có table table_identifier, bảng này sử dụng để quản lý các id tự tăng của các Entity. Cấu trúc table này như sau:
Mỗi lần 1 Category được thêm vào database, giá trị value_column_name trong table table_identifier ứng với column_name=category sẽ được cộng thêm 5 (allocationSize) và giá trị này sẽ là id của record được thêm vào table category.
UUID
UUID là một lớp của Java cho phép bạn tạo ra một chuỗi 36 ký tự ngẫu nhiên. Và với 36 ký tự xác suất trùng nhau là vô cùng bé. Chúng ta có thể sử dụng UUID với @GeneratedValue để Hibernate tạo ra một chuỗi ngẫu nhiên kiểu này gán cho giá trị của cột.
Ví dụ:
@Entity
@Table
public class UserVerification {
@Id
@GeneratedValue
private UUID id;
private String value;
}
@Lob
@Lob thường chú thích cùng với @Column để nói rằng cột đó có kiểu BLOB hoặc CLOB. Trong một số Database có phân biệt TINY, MEDIUM, LARGE BLOB/CLOB, còn một số database thì không.
Phần tử length trong @Column trong trường hợp này sẽ quyết định nó map vào BLOB/ CLOB nào. Trong trường hợp cho phép BLOB/CLOB tối đa hãy để length = Integer.MAX_VALUE.
Ví dụ:
@Entity
@Table
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Lob
@Column(name = "avatar", nullable = true, length = Integer.MAX_VALUE)
private byte[] avatar;
}
@ManyToOne
@ManyToOne mô tả một quan hệ N-1 (Nhiều – Một), nó thường được sử dụng cùng với @JoinColumn.
Hibernate có các công cụ cho phép tạo ra các lớp Entity từ các bảng trong Database và Hibernate cũng cho phép tạo ra bảng từ các lớp Entity, bao gồm cả giàng buộc giữa các bảng (Foreign Key). Annotation @ForeignKey cho phép chỉ định rõ tên Foreign Key sẽ được tạo ra.
FetchType.LAZY
LAZY nói với Hibernate rằng, hãy tải dữ liệu một cách lười biếng, nghĩa là chỉ tải khi được gọi (khi cần thiết).
Chẳng hạn bạn có một đối tượng Account, và gọi phương thức getOpenBranch() nó trả về một đối tượng Branch, đối tượng Branch chỉ trường (field) branchId được gán giá trị, các trường khác thì không.
Thực tế hibernate chưa tải dữ liệu từ bản ghi tương ứng của bảng BRANCH vào đối tượng này. Nó chỉ thực hiện truy vấn dữ liệu khi bạn làm gì đó với đối tượng Branch vừa có được, chẳng hạn gọi phương thức branch.getName().
FetchType.EAGER
EAGER nói với Hibernate rằng, hãy truy vấn toàn bộ các cột của bảng liên quan.
Chẳng hạn bạn có đối tượng Account, và gọi phương thức getOpenBranch() trả về đối tượng Branch đã có sẵn các giá trị cho các trường ( name, address, …). Thực tế dữ liệu của nó có được cùng trong 1 lần truy vấn với bảng Account.
Lưu ý: nên sử dụng LAZY thay vì EAGER vì lý do hiệu năng chương trình.
@Entity
@Table
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// ...
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "category_id", nullable = false,
foreignKey = @ForeignKey(name = "fk_post_category"))
private Category category;
}
@OneToMany
@OneToMany mô tả quan hệ 1-N (Một – Nhiều). Nó là đảo ngược của @ManyToOne, và vì vậy nó dựa vào @ManyToOne để định nghĩa ra @OneToMany.
@Entity
@Table
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
private Set posts;
}
@OneToOne
@OneToOne mô tả quan hệ 1-1 (Một – Một).
@Entity
@Table(name = "user_profile")
public class UserProfile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// ...
@OneToOne(fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "fk_user_profile"))
private User user;
}
@Entity(name = "User")
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// ...
@OneToOne(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
private UserProfile userProfile;
}
@ManyToMany
@ManyToMany mô tả quan hệ N-N (Nhiều – Nhiều).
@Entity
@Table
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "roles")
private Set users;
}
@Entity(name = "User")
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// ...
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "user_roles",
joinColumns = { @JoinColumn(name = "user_id", nullable = false, updatable = false) },
inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) })
private Set roles;
}
@OrderBy
@OrderBy được sử dụng để sắp xếp một danh sách, vì vậy nó có thể được sử dụng cùng với @OneToMany, @ManyToMany.
@Entity
@Table
public class Category {
// ...
@OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
@OrderBy("title")
private Set posts;
}
Trên đây là các Annotation thường được sử dụng để tạo các Hibernate Entity cho các database table. Trong các bài viết kế tiếp, tôi sẽ hướng dẫn các bảng tạo Hibernate Entity một cách tự động từ table có sẵn, chúng ta không cần tạo Entity một cách thủ công.
Token introspection với Spring Authorization Server
Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Để kiểm tra một access token có còn valid hay không, có expired chưa, có bị revoke hay chưa, có phải do Authorization Server của chúng ta issue hay không, chúng ta sẽ sử dụng endpoint token introspection của Authorization Server để làm điều này.
Lưu ý là khi setup Authorization Server sử dụng Spring Authorization Server, các bạn cần cung cấp thông tin issuer bằng cách khai báo một bean của class ProviderSettings, ví dụ như sau:
Những element nào đang được áp dụng CSS container query sẽ được đánh dấu
4. Invert checkbox cho network filter
Ví dụ chúng ta muốn lọc tất cả những request nào có status không phải là 404, đầu tiên filter tất cả những request có status là 404 bằng status-code:404 sau đó check vào ô invert
5. Bỏ console sidebar
Thay sidebar này bằng bộ filter trực tiếp trên thanh toolbar nằm ngang
6. Thay đổi định dạng color trên cửa sổ Computed
Để thay đổi sang một định dạng khác, click giữ Shift + ô màu
Để trãi nghiệm ngay những tính năng này các bạn có thể dùng bản Chrome Canary
Windows 10: Tìm lại các cửa sổ “lạc trôi” mất trong quá trình sắp xếp
Bài viết được sự cho phép của blogchiasekienthuc.com
Đa nhiệm là một trong những khả năng rất tuyệt vời có trên hệ điều hành Windows 10 nói riêng và tất cả các hệ điều hành (như, iOS, Android, Ubuntu, macOS…) nói chung.
Bạn có thể làm việc cùng lúc với nhiều chương trình, nhiều cửa sổ khác nhau nếu màn hình đủ rộng và cấu hình máy tính đủ mạnh, giúp nâng cao hiệu quả công việc và giảm đáng kể thời gian làm việc so với trước đây.
Chính vì có thể mở rất nhiều của sổ cùng lúc nên việc sắp xếp ngăn nắp các cửa sổ làm việc là điều cần thiết, trong quá trình kéo qua kéo lại các cửa sổ để sắp xếp thì không ít lần một trong số các cửa sổ làm việc của mình bị “lạc trôi” và thế là phải mở lại chương trình từ đầu :((
Thế nên trong bài viết này mình sẽ chia sẻ cho các bạn vài cách tìm lại các cửa sổ bị thất lạc, mình hay gọi là “lạc trôi” mất trên Windows 10 nhé !
I. Cách tìm lại các cửa sổ bị “lạc trôi” trong quá trình sử dụng Windows
“Lạc trôi” được hiểu theo đúng nghĩa đen của nó, tức là mất hút trên màn hình luôn. Bạn không thể mở lại dù biểu tượng ở dưới thanh taskbar vẫn còn, cũng không thể dùng chuột để kéo nó trở lại được.
Trường hợp này thì người ta thường phải sử dụng Task Manager để tắt ứng dụng đi, sau đó mở lại phần mềm đó từ đầu, rất mất thời gian mà lại còn có thể làm mất những dữ liệu đang làm việc dở, chưa kịp lưu lại nữa.
Nguyên nhân của tình trạng này có thể là do khi bạn sử dụng nhiều màn hình, khi kéo cửa sổ từ màn hình này sang màn hình kia thì nó đột nhiên bị tắt đi.
Cũng tương tự khi bạn dùng Laptop cắm ra màn hình ngoài ở chế độ (Project Mode) là Extend, nếu bạn để các cửa sổ ở màn hình ngoài xong bạn ngắt kết nối thì bạn cũng không thể thấy các cửa sổ đó ở trên màn hình Laptop được nữa – mặc dù nó vẫn đang chạy.
Nhưng bạn cũng đừng lo vì dưới đây mình đã tổng hợp lại cho các bạn những cách đơn giản và nhanh nhất để giúp khắc phục lỗi này.
Cách #1: Sử dụng tính năng sắp xếp tự động của Windows 10
Thực ra tính năng này đã có từ Windows 7 rồi, nhưng khá ít người sử dụng mặc dù bạn có thể kích hoạt nó rất nhanh chóng từ thanh Taskbar của Windows 7 và cả Windows 10 nữa.
Tuy nhiên, bạn phải có cửa sổ đang mở trên màn hình Desktop thì những tính năng này mới hiện lên để chọn nha.
Nếu những dòng này không hiện thì bạn phải mở một cửa sổ hay chương trình nào đó, ví dụ như File Explorer (Windows + E), Task Manager,.. thì những tính năng mới chọn được.
Bạn hãy chọn 1 trong 3 dòng này, cái nào cũng được hết vì khi lấy lại được cửa sổ bị mất đó rồi thì cũng không cần thiết sử dụng tính năng này nữa.
Nếu bạn chọn dòng 1:[Cascade Windows] thì tất cả các cửa sổ đang mở sẽ được sắp xếp theo dạng thác nước từ trên xuống, kiểu vậy. Để biết chi tiết hơn thì bạn hãy thử trực tiếp hoặc xem hình dưới.
Để tắt chế độ này thì cách đơn giản nhất là bạn kéo các cửa sổ ra chỗ khác trên màn hình hoặc click chuột phải lại vào thanh Taskbar => và chọn Undo Cascade all Windows nhé.
Tiếp theo, nếu bạn chọn dòng 2: [Show Windows Stacked] thì các cửa sổ sẽ được sắp xếp từ trên xuống, kín màn hình desktop của các bạn luôn.
Để bỏ kích hoạt chế độ sắp xếp này cũng click chuột phải vào thanh Taskbar => và chọn Undo Show all windows stacked là xong.
Cuối cùng, nếu bạn bấm vào [Show Windows Side by side] thì Windows sẽ gọi ra và sắp xếp lại các cửa sổ theo kiểu cột dọc từ trái sang kín màn hình, thay vì sắp từ trên xuống như Stacked Windows.
Sau khi đã lấy lại được cửa sổ làm việc mong muốn rồi thì bạn hãy click chuột phải lên thanh Taskbar => chọn Undo show all windows side by side để bỏ chế độ sắp xếp tự động của Windows.
Cách #2: Sử dụng menu SHIFT + Chuột phải
Nếu như các bạn chưa biết thì khi click chuột phải vào góc trái của một cửa sổ bất kỳ => sẽ có một menu xuất hiện, trong đó có các tính năng như: Phóng to, thu nhỏ, thu nhỏ xuống Taskbar, đóng và tất nhiên là có di chuyển cửa sổ nữa.
Tính năng di chuyển cửa sổ này giống như khi bạn click chuột lên tiêu đề của cửa sổ rồi kéo nó đi vậy, có thể giúp chúng ta kéo những cửa sổ bị “lạc trôi” trở lại màn hình.
Thật may là chúng ta vẫn còn có cách khác để kích hoạt menu này, bạn chỉ cần giữ phím SHIFT => rồi click chuột phải lên biểu tượng của phần mềm có cửa sổ bị mất ở dưới thanh Taskbar.
Sẽ có một menu tương tự gồm những chức năng mà mình kể trên xuất hiện => bạn bấm chọn dòng Move.
Ngay lập tức, con trỏ chuột sẽ biến thành biểu tượng mũi tên 4 chiều để di chuyển như hình bên dưới, bây giờ bạn có thể di chuyển đến vị trí của cửa sổ bị mất.
Việc bạn phải làm lúc này đó là giữ chuột và kéo cửa sổ đó về màn hình chính. Nếu chưa được thì cứ lặp lại đến khi nào kéo được nó ra màn hình chính nhé !
Cách #3. Chuyển chế độ hiển thị (nên thử trước)
Bạn nên thử cách làm này trước, nếu bạn đang thiết lập chế độ 2 màn hình thì bạn hãy thiết lập lại bằng cách nhấn tổ hơn phím Windows + Pcccccc
=> Okay, bây giờ bạn hãy chọn một trong 2 chế độ:
PC screent only: Chỉ hiện thị nội dung trên màn hình máy tính.
Duplicate: Hiển thị nội dung trên cả 2 màn hình.
II. Lời kết
Vâng, như vậy là mình đã hướng dẫn xong cho các bạn cách tìm lại những cửa sổ đang bị “lạc trôi” mất trong quá trình làm việc với máy tính Windows 10 một cách hiệu quả nhất rồi nhé.
Thật sự thì thật khó để mô tả ngắn gọn lỗi này trong tiêu đề bài viết, nên có thể nhiều bạn đọc tiêu đề vài lượt cũng không hiểu gì đâu. Mình biết chứ 🙂
Nhưng nếu đọc chi tiết nội dung thì mình tin là bạn đã hiểu tường tận rồi phải không ạ !
Nếu thấy bài viết này hay và có ích thì đừng quên đánh giá bài viết này cũng như chia sẻ đến cho người khác cùng biết. Chúc các bạn thành công !
Deploy ứng dụng load balancer sử dụng Nginx với Docker
Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Load balancer là một khái niệm về cân bằng tải, được sử dụng để giúp ứng dụng của chúng ta có thể handle một số lượng lớn các request từ người dùng. Chúng ta sẽ deploy ứng dụng của mình lên nhiều máy khác nhau, behind một load balancer, các request từ người dùng sẽ gọi tới load balancer và sẽ được load balancer forward tới một trong các máy này… Nginx là một trong những web server có thể hỗ trợ chúng ta hiện thực phần load balancer đó các bạn! Cụ thể như thế nào? Trong bài viết này, mình sẽ hướng dẫn các bạn deploy ứng dụng load balancer sử dụng Nginx với Docker các bạn nhé!
Để làm ví dụ cho bài viết này, mình sẽ sử dụng Docker Compose để mô phỏng một mô hình deploy sử dụng load balancer. Mình sẽ deploy ứng dụng ví dụ trong bài viết Giới thiệu về Docker Compose trên 3 container khác nhau sử dụng chung một PostgreSQL, một Nginx container làm nhiệm vụ load balancer forward request của người dùng tới 1 trong 3 container này:
Ứng dụng ví dụ
Với ứng dụng ví dụ, để biết Ngnix đang forward request của người dùng tới instance nào, mình sẽ add thêm code trong phương thức helloDockerCompose() của request “/hello” in ra dòng log “Received request …” như sau:
package com.huongdanjava.springboot;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.zaxxer.hikari.HikariDataSource;
@SpringBootApplication
@RestController
public class SpringBootDockerComposeApplication {
private static final Logger LOGGER =
LoggerFactory.getLogger(SpringBootDockerComposeApplication.class);
@Autowired
private DataSource dataSource;
@RequestMapping("/hello")
public String helloDockerCompose() {
LOGGER.info("Received request ...");
Integer idleConnection =
new HikariDataSourcePoolMetadata((HikariDataSource) dataSource).getIdle();
return "Hello Docker Compose! Idle connection to database is " + idleConnection;
}
public static void main(String[] args) {
SpringApplication.run(SpringBootDockerComposeApplication.class, args);
}
}
Khi chạy ứng dụng, chúng ta sẽ take a look vào Console của Docker Compose để biết là request đang được forward tới container nào.
Hãy build lại Docker Image cho ứng dụng ví dụ của chúng ta các bạn nhé!
Cấu hình của ứng dụng ví dụ cho 3 container tương ứng với 3 services trong tập tin docker-compose.yml, trong bài viết Giới thiệu về Docker Compose sẽ như sau:
Mỗi container sẽ expose port khác nhau bao gồm: 8081, 8082 và 8083.
Cấu hình của PostgreSQL database trong tập tin docker-compose.yaml, không đổi các bạn nhé!
Nginx
Trước khi đi vào chi tiết cấu hình load balancer với Nginx như thế nào, chúng ta sẽ điểm sơ qua một số thuật toán được sử dụng để hiện thực load balancer các bạn nhé! Chúng ta có một số thuật toán cơ bản sau:
Round Robin: các request từ người dùng sẽ được forward lần lượt đến tất cả các máy theo thứ tự. Có nghĩa là ứng dụng của chúng ta được deploy lên bao nhiêu máy thì request của người dùng sẽ lần lượt được forward đến tất cả các máy này. Request đầu tiên sẽ vào máy 1, request thứ 2 sẽ vào máy 2, … sau khi máy cuối cùng được sử dụng thì request tiếp theo sẽ vào máy 1.
Weighted Round Robin: tương tự như thuật toán Round Robin nhưng các máy deploy ứng dụng sẽ có cấu hình khác nhau. Máy nào có cấu hình cao hơn sẽ được đánh trọng số cao hơn và nhận được nhiều request hơn các bạn nhé!
Dynamic Round Robin: thuật toán này giống như Weighted Round Robin nhưng có sự khác biệt là trọng số của các máy sẽ không cố định. Cấu hình của các máy sẽ được kiểm tra liên tục, do đó trọng số sẽ thay đổi liên tục.
Fastest: thuật toán này dựa vào thời gian response của máy trong setup load balancer. Máy nào có thời gian response nhanh hơn sẽ được chọn để forward request.
Least Connections: máy nào có ít kết nối nhất sẽ được forward request tới.
Trong bài viết này, mình sẽ sử dụng thuật toán Round Robin với Nginx để làm ví dụ các bạn nhé!
FROM nginx:latest
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
trong đó, tập tin nginx.conf có nội dung như sau:
upstream apps {
server 172.17.0.1:8081;
server 172.17.0.1:8082;
server 172.17.0.1:8083;
}
server {
location / {
proxy_pass http://apps;
}
}
Trong tập tin nginx.conf trên, mình đã sử dụng reverse proxy của Nginx với directive upstream để hiện thực load balancer. Khi một request từ người dùng đến, request này sẽ được forward một trong 3 server được khai báo bên trong directive upstream này. Mặc định thì Nginx hỗ trợ thuật toán round-robin nên các bạn không cần khai báo gì thêm ngoài thông tin của 3 server.
Cũng cần nói thêm là khi start các container 172.17.0.1 là địa chỉ IP mặc định khi các container được start, nên như các bạn thấy, mình sử dụng 172.17.0.1 cho 3 container của ứng dụng ví dụ, với các port khác nhau như đã khai báo trong tập tin docker-compose.yaml.
Các bạn cần build custom Docker image này bằng câu lệnh sau:
docker build -t nginx:0.0.1 .
Kết quả:
Sau khi đã có Docker Image của Nginx, các bạn có thể khai báo một service cho Nginx trong tập tin docker-compose.yaml như sau:
nginx:
image: nginx:0.0.1
ports:
- 80:80
Đến đây thì chúng ta đã hoàn thành việc cấu hình để deploy load balancer cho ứng dụng ví dụ của chúng ta. Nội dung của tập tin docker-compose.yaml lúc này như sau:
Chạy tập tin này với docker compose up, các bạn sẽ thấy kết quả như sau: Lúc này, nếu các bạn request tới http://localhost/hello lần thứ nhất, các bạn sẽ thấy Console của Docker Compose có kết quả như sau:
Container spring_boot_docker_compose_1 đã handle request này.
Lần thứ 2:
Lần này thì container spring_boot_docker_compose_2 handle request.
Lần thứ 3:
Và lần thứ tư sẽ quay lại spring_boot_docker_compose_1:
Giờ chúng ta muốn can thiệp vào phương thức get (khi chúng ta gọi object.prop)
let number =[0,1,2]
numbers =newProxy(numbers,{get(target, prop){if(prop in target){return target[prop];}else{return0}}})alert(numbers[1]);// 1alert(numbers[123]);// 0
Ví dụ khác, chúng ta có một dãy số, chỉ cho phép thêm vào kiểu number, nếu cố tình thêm vào một kiểu dữ liệu khác sẽ không thực hiện được và trả về lỗi
let numbers =[];
numbers =newProxy(numbers,set(target, prop, val){if(typeof val =='number'){
target[prop]= val;returntrue;}else{// trả về lỗireturnfalse;}}})
numbers.push(1);// oknumbers.push('test');// TypeError ('set' on proxy returned false)
Một ứng dụng khác, bảo vệ các thuộc tính internal của một object, ví dụ chúng ta có một số property bắt đầu bằng _, chúng ta không cho phép truy cập các property
let user ={
name:"John",
_password:"****"}
user =newProxy(user,{get(target, prop){if(prop.startWith('_')){thrownewError("Access denied");}let value = target[prop];return(typeof value ==='function')?value.bind(target): value;},set(target, prop, val){if(prop.startsWith('_')){thrownewError("Access denied");}else{
target[prop]= val;returntrue;}},deleteProperty(target, prop){if(prop.startsWith('_')){thrownewError("Access denied");}else{delete target[prop];returntrue;}},ownKeys(target){return Object.keys(target).filter(key=>!key.startsWith('_'));}})alert(user._password);// Error: Access denieddelete user._password;// Error: Access denied
Nếu object của chúng ta là một function thì sao nhỉ?
Ví dụ với hàm delay sau, hàm này cho phép delay thời gian hàm được thực thi bằng setTimeout
Chúng đã đề cập đến các phương thức tiền xử lý ownKeys, deleteProperty, get, set, apply. Ngoài ra nó còn có các phương thức khác các bạn có thể thảm khảo thêm
Trải Nghiệm Môi Trường Work:Live:Learn Tại ACB Với Những Hoạt Động Đầy Màu Sắc Và Thú Vị
ACB xây dựng môi trường làm việc tích cực với những hoạt động sôi nổi theo tam giác kết nối với tên gọi Work:Live:Learn (Công việc x Cuộc sống x Học tập) để thúc đẩy cho sự phát triển bền vững của mỗi Đối Tác Sự Nghiệp trong hệ thống, cùng các thành phần hữu quan khác với tổ chức.
Làm việc hiệu quả, dẫn dắt tương lai
Bên cạnh các công việc đảm bảo tính vận hành của hệ thống, ACB hướng nhân viên chuyển dịch tỉ trọng công việc thực hiện theo định hướng hỗ trợ cho các chiến lược trung và dài hạn của ngân hàng. Để thực hiện điều đó, mỗi ACBer được khuyến nghị nắm vững thông tin về thẻ điểm cân bằng BSC (Balance Scorecard), bám sát các mục tiêu chung để được đánh giá và đo lường hiệu quả công việc.
ACB tập trung đầu tư vào việc xây dựng kế hoạch phát triển lực lượng lao động phù hợp bằng cách cơ cấu, phân bổ nhóm nhân tài theo những chương trình, hoạt động khác nhau để tạo ra tác động hiệu quả, kích hoạt năng lực toàn diện của cá nhân, đơn vị đội nhóm và tổ chức. Đặc biệt, ACB chú trọng thúc đẩy sự hợp tác mạnh mẽ trong tổ chức bằng cách áp dụng chặt chẽ quy trình phối hợp DSOC (Delta force – Support team – Owner – Control), đa dạng hóa kênh tương tác và công cụ triển khai công việc. Bên cạnh đó thường xuyên thực hiện các khảo sát ghi nhận đánh giá từ các thành phần hữu quan giúp ACB liên tục cải tiến sản phẩm và chính sách, đảm bảo công việc thực hiện phù hợp với kỳ vọng của tổ chức.
Với tham vọng trở thành tổ chức dẫn đầu trên thị trường tại các phân khúc chuyên biệt, ACB không ngừng đầu tư vào hệ thống lõi (Core banking), cơ sở hạ tầng và tận dụng dữ liệu trong việc ra các quyết định. Bên cạnh tập trung vào 5 giá trị cốt lõi để phát triển tổ chức bền vững, ACB cũng khuyến khích xây dựng văn hoá Agile trong từng đơn vị bằng các chính sách và công cụ để kịp thời thích ứng với thị trường và nâng cao năng lực cạnh tranh.
Sống khỏe, trách nhiệm & tích cực
Các thành viên ACB được khuyến khích hướng đến việc xây dựng cuộc sống có trách nhiệm, lành mạnh và tích cực. Dựa trên BSC ghi nhận kết quả cam kết, ACB không chỉ đảm bảo cho nhân viên chế độ thu nhập, thưởng công bằng và minh bạch, được điều chỉnh cạnh tranh với thị trường, mà còn mang đến những những chính sách phúc lợi hấp dẫn khác đầu tư qua các hoạt động phát triển kinh doanh và chăm sóc nhân viên chu đáo hơn. Bên cạnh đó, mong muốn truyền đi những thông điệp tích cực và đóng góp vào việc xây dựng tương lai bền vững, tất cả người ACB đều ý thức rất rõ vai trò của mình và nhiệt tình tham gia trong công tác bảo vệ môi trường như giảm thiểu nhựa, trồng cây, truyền thông bảo tồn động vật quý hiếm với chiến dịch Gần lại O được thực hiện suốt hơn 7 năm qua.
Sức khoẻ thể chất nhân viên cũng là phần quan trọng mà ACB hướng đến. Từ năm 2021, ACB đã áp dụng cho tất cả nhân viên chế độ phát triển cân bằng cung cấp thông tin việc giải mã Gen, tìm hiểu chế độ dinh dưỡng phù hợp và tạo dựng phong cách sống lành mạnh với các hoạt động nâng cao. Bên cạnh đó, nội bộ ngân hàng cũng tổ chức nhiều hoạt động thú vị như: Uniform Challenge, ACB In a day ghi lại những khoảnh khắc ấn tượng của người ACB, nhật ký làm việc hay các sự kiện dành cho các thành viên khác trong gia đình.
Hoàn thiện năng lực, vươn tầm chuyên gia
ACB hành động và không ngừng xây dựng trở thành một tổ chức học tập. Nơi mà mỗi ACBers là một người học tích cực, chủ động với nhiệm vụ ngày càng nâng cao năng lực, hoàn thiện bản thân, đáp ứng nhu cầu công việc, và trên hết nỗ lực vượt trội để trở thành chuyên gia trong các mảng lĩnh vực phụ trách. Tính làm chủ và kết nối giữa học tập công việc được kích hoạt mạnh mẽ tạo nên sự phát triển bền vững cho cá nhân, đơn vị đội nhóm và tổ chức.
Việc học ở tại ACB được thúc đẩy thực hiện với nhiều phương pháp khác nhau, đặc biệt là học tập kết hợp (Blended learning) tạo nền tảng ứng dụng Learn:Do:Share để có thể lan tỏa kiến thức kinh nghiệm cùng đồng nghiệp, phác thảo chủ đề học tập phù hợp cho hệ thống và cùng ACB mở rộng cộng đồng học tập theo nhiều hình thức và nội dung. Bên cạnh đó, ACB liên tục cải tiến hành vi học tập trực tuyến, xây dựng các nội dung học tập theo hướng cá nhân hóa theo từng vị trí công việc, thiết kế kế hoạch học tập dựa trên lộ trình phát triển nghề nghiệp, đồng thời đa dạng hóa danh mục học tập.
Mô hình Work:Live:Learn tích hợp trong mọi hoạt động nhằm mang lại trải nghiệm hài hòa và liền mạch cho tất cả các thành viên trong hệ thống từ lãnh đạo đến nhân viên, kể cả những người mới làm việc. ACB mong muốn tạo ra một môi trường nơi bạn được truyền cảm hứng để làm tốt nhất công việc của mình. Trong chặng đường sắp tới của ACB, chúng ta sẽ là một, cùng nhau đồng hành đưa ACB trở thành một ngân hàng phát triển bền vững, chất lượng và an toàn.
Làm thế nào để khôi phục giao diện cũ trên Firefox 92?
Bài viết được sự cho phép của blogchiasekienthuc.com
Firefox từ trước tới nay vẫn luôn nằm trong top những trình duyệt web phổ biến nhất trên máy tính, đặc biệt là trên Ubuntu vì nó vốn là trình duyệt mặc định của hệ điều hành này.
Nhưng trong 3 năm trở lại đây, chú “cáo lửa” đang tỏ ra yếu thế khi đã mất tới hơn 46 triệu người dùng thường xuyên, từ 244 triệu người dùng giảm xuống còn 198 triệu người dùng tính tới đầu quý II năm nay.
Đặc biệt là từ lúc xuất hiện trình duyệt Microsoft Edge Chromium của Microsoft, đã làm cho thị phần của Chrome sụt giảm nhẹ và càng làm cho Firefox thất thế hơn.
Ngoài ra, giao diện mới vừa được cập nhật của Firefox mang tên Proton cũng khiến không ít người dùng nói lời từ biệt với trình duyệt web này.
Và nếu như bạn cũng là một người đã từ bỏ hoặc đang dùng Firefox nhưng không ưa giao diện mới cho lắm thì bài viết này sẽ hướng dẫn cho các bạn chi tiết cách để có thể khôi phục lại giao diện cũ của Firefox nhé !
#1. Lý do mình muốn khôi phục giao diện cũ trên Firefox 92
Như đã nói ở đầu bài viết, Firefox kể từ phiên bản 89 đã được cập nhật giao diện mới với tên gọi là Proton.
Proton UI thực sự mang đến một làn gió mới cho trình duyệt này, với phong cách thiết kế tối giản cùng các góc được bo cong thay vì vuông vức như trước tạo nên một sự kết hợp hoàn hảo giữa Windows 11 và Firefox.
Nhưng không phải tự nhiên mà giao diện này bị người ta chê thậm tệ tới vậy, Proton UI có kha khá nhược điểm mà nếu không thay đổi sớm thì có lẽ Firefox sẽ mất rất nhiều người dùng nữa.
Một trong số đó có thể kể đến như độ tương phản trong thiết kế quá thấp, phần danh sách các Tabs ở trên thì trông giống một cái nút hơn, nó nổi lên, tách biệt hẳn với phần giao diện còn lại và chiếm quá nhiều diện tích.
Thêm nữa, việc loại bỏ hết các icon trong phần menu tùy chọn là một nước đi không sáng suốt của đội ngũ phát triển giao diện của Firefox. Theo cá nhân mình đánh giá là như vậy !
Và còn rất nhiều cái khác nữa mà mình không tiện kể trong bài viết này, mà cũng chẳng cần quan tâm làm gì vì chúng ta sẽ đi khôi phục giao diện cũ ngay bây giờ !
#2. Hướng dẫn thực hiện khôi phục giao diện cũ trên Firefox 92
+ Bước 1: Ở giao diện chính của trình duyệt, gõ vào thanh địa chỉ about:config để mở những thiết lập nâng cao cũng như tính năng thử nghiệm của Firefox.
Cái này hoàn toàn tương tự khi bạn truy cập địa chỉ chrome:flags trên Google Chrome và Microsoft Edge.
Bạn sẽ nhận được cảnh báo về việc thay đổi những thiết lập trong đây sẽ có thể ảnh hưởng tới hiệu năng cũng bảo mật của Firefox, tiếp tục bằng cách bấm vào nút Accept the Risk and Continue.
Hoặc bạn có thể bỏ tích ở dòng Warn me when I attempt to access these preferences để bỏ qua luôn thông báo này cho những lần truy cập sau ha.
+ Bước 2: Bạn dán từ khóa toolkit.legacyUserProfileCustomizations.stylesheets vào ô tìm kiếm.
=> Sau đó bấm vào nút Toggle ở bên phải để chuyển giá trị của tùy chọn toolkit.legacyUserProfileCustomizations.stylesheets thành true.
Tiếp theo bạn hãy khởi động lại trình duyệt Firefox để thay đổi này có hiệu lực.
+ Bước 3: Tải xuống bản fix giao diện Proton và giúp khôi phục về Photon (tên của giao diện cũ được dùng tới bản 88) của tác giả black7375 trên Github bằng một trong các đường link dưới đây :
Tải xong bạn hãy giải nén nó ra vị trí bất kỳ => sau đó đổi tên thư mục vừa giải nén thành chrome nha. Mình sẽ giải nén nó ra màn hình Desktop để tí nữa tiện sử dụng.
+ Bước 4: Tiếp tục quay lại trình duyệt Firefox, bạn gõ vào thanh địa chỉ about:support => rồi bấm Enter để truy cập trang thông tin chi tiết như bản build, các driver được sử dụng,… của trình duyệt.
Bạn kéo xuống dưới và bấm vào nút Open Folder trong mục Profile Folder để mở thư mục Profile Folder của FireFox trong File Explorer.
+ Bước 5: Giờ hãy copy thư mục chrome đã giải nén ở Bước 3 và dán vào thư mục Profile Folder này. Sau đó hãy truy cập vào thư mục chrome.
+ Bước 6: Ở đây bạn chọn file có tên user.js => rồi bấm Ctrl + X hoặc nút Cut trên thanh công cụ của File Explorer để Cut.
+ Bước 7: Quay lại thư mục Profile Folder lúc nãy bằng cách bấm nút Back trên thanh địa chỉ của File Explorer và dán file user.js vào đây.
+ Bước 8: Cơ bản là xong rồi, giờ bạn có thể khởi động lại Firefox để thấy được sự thay đổi về giao diện.
Nhưng để cho chắc ăn, bạn hãy quay trở lại trang about:support và thực hiện xóa Cache bằng cách bấm vào nút Clear startup cache…. Trình duyệt cũng sẽ khởi động lại ngay sau đó.
+ Bước 9: Và cuối cùng, giao diện quen thuộc ngày nào của Firefox đã quay trở lại. Tất nhiên, đây không hoàn toàn là giao diện Photon cũ mà là một sự kết hợp của những ưu điểm mà 2 giao diện Photon cũ và Proton mới có.
#3. Lời kết
Như vậy là mình đã vừa hướng dẫn xong cho các bạn cách để quay về giao diện cũ trên phiên bản Firefox 92 rồi nhé.
Hy vọng là trong thời gian tới đội ngũ phát triển giao diện của Firefox sẽ chú ý tới vấn đề này hơn và sớm thay đổi nó. Nếu thấy bài viết này hay đừng quên chia sẻ cho mọi người cùng biết nha. Chúc các bạn thành công !
Bài viết được sự cho phép của tác giả Kien Dang Chung
Trong thời gian gần đây, công đồng lập trình web thường nhắc đến một framework có tên Vue.js cũng như bàn luận rất nhiều về các ưu điểm của nó khi so sánh với các framework đã có mặt từ rất lâu như jQuery, React (được hỗ trợ bởi Facebook), Angular (được hỗ trợ bởi Google)… Vậy Vue.js là gì? tại sao nó phát triển một cách mạnh mẽ như vậy, câu trả lời có trong phần tiếp theo.
Vue (phiên âm /vjuː/, đọc giống như từ view) là một framework Javascript tiên tiến trong xây dựng giao diện người dùng, không giống như các framework khác, Vue được xây dựng từ những dòng code cơ bản nhất nhằm tối ưu tốc độ. Thư viện của Vue chỉ tập trung vào lớp hiển thị, rất đơn giản để tiếp cận và dễ dàng tích hợp vào các hệ thống khác. Vue cũng có khả năng cung cấp các ứng dụng web đơn trang Single Page Application (toàn bộ website chỉ là một trang) cho phép kết hợp với nhiều các công cụ hiện đại, như Laravel chẳng hạn.
Vue.js được sử dụng để xây dựng giao diện người dùng giống như React (sử dụng bởi Facebook), Angular (được hậu thuẫn bởi Google), Ember… Tuy nhiên, Vue.js có tốc độ tạo trang (render) rất nhanh và chiếm khá ít bộ nhớ. Chúng ta có thể xem bảng benchmark các framework Javascript nổi tiếng nhất hiện nay, Vue có một thứ hạng không tồi chút nào.
Vue.js mới chỉ ra mắt năm 2015, nhưng Vue.js đã sớm khẳng định mình và sớm trở thành người thay thế Angular và React, đây cũng chính là lý do Laravel giới thiệu Vue.js trong thiết lập mặc định.
Mô hình MVVM
MVVM là viết tắt của Model-View-ViewModel là một mô hình được áp dụng trong framework Vue.js.
Trong mô hình này, dữ liệu mỗi khi được “gán” vào View hoặc Model sẽ đều được Vue.js tự động gắn cho phần còn lại. Tức là khi dữ liệu thay đổi ở Model nó sẽ tự động được “cập nhật” sang View và khi người dùng thay đổi dữ liệu trên View (ví dụ nhập liệu vào ô địa chỉ email chẳng hạn) thì dữ liệu cũng được tự động cập nhật ngược lại Model. Trong cộng đồng Vue.js thường gọi mô hình này với một thuật ngữ khác là two-way data binding, tạm gọi là gán dữ liệu hai chiều. Chúng ta sẽ cùng tìm hiểu mô hình này trong ví dụ đầu tiên sử dụng Vue.js ở phần tiếp theo.
Ví dụ đầu tiên sử dụng framework Vue.js
Thành một thói quen, tất cả các ngôn ngữ lập trình khi bắt đầu học, chúng ta đều có ví dụ đầu tiên Hello world. Nó giúp chúng ta có cái nhìn cơ bản về một ngôn ngữ, nào chúng ta cùng bắt tay vào một ví dụ hiển thị một lời chào “Xin chào, tôi là framework Vue.js”.
<!DOCTYPE html><html><head><title>Ví dụ đầu tiên Vue.js - allaravel.com</title></head><body><div id="app"><h1>{{ message }}</h1><input v-model="message"></div><script src="https://vuejs.org/js/vue.min.js"></script><script type="text/javascript">newVue({
el:'#app',
data:{
message:'Xin chào, tôi là Vue.js'}})</script></body></html>
Ngay từ đầu, đối tượng message trong Model có giá trị “Xin chào, tôi là Vue.js” ngay lập tức giá trị của nó được hiển thị lên thẻ <h1> trên View thông qua cú pháp {{ message }}. Ô nhập liệu <input> cũng được gán với đối tượng message, do vậy ngay khi thay đổi giá trị trong thẻ <input> này, DOM Listener sẽ cập nhật giá trị đối tượng message ngược lại Model, và cũng ngay lập tức giá trị của đối tượng message cũng được cập nhật đến các View có tham chiếu đến message, mà ở đây là thẻ <h1>.
Ví dụ đầu tiên này đã phần nào giúp bạn hiểu được mô hình MVVM hay thuật ngữ gán dữ liệu hai chiều (two-way data binding). Tạm khép lại việc viết code trong Vue.js trong bài viết này.
Kiến thức cần thiết cho Vue.js
Sử dụng Vue.js nói riêng hay phát triển các ứng dụng web nói chung đòi hỏi khá nhiều các kiến thức cơ bản khác nhau, dưới đây là các kiến thức bạn nên có khi làm việc với Vue.js. Có thể có một số kiến thức không liên quan trực tiếp nhưng trong khuôn khổ loạt bài viết về Vue.js của Allaravel, bạn nên tìm hiểu:
Kiến thức
Mô tả
Mức độ quan trọng
Độ khó
Ngôn ngữ HTML (Hyper Text Markup Language) là ngôn ngữ đánh dấu siêu văn bản
Ngôn ngữ này là nền tảng khi thiết kế web
6
5
Ngôn ngữ CSS (Cascading Style Sheets)
Ngôn ngữ này giúp cho website của bạn đẹp hơn, đặc biệt khi hiện nay website cần thiết kế cuốn hút.
6
6
Framework Bootstrap
Framework CSS này giúp cho việc phát triển giao diện đơn giản và có thể phù hợp với mọi thiết bị, đặc biệt là hiện nay điện thoại thông minh được sử dụng rất nhiều, website cần tương thích hoàn toàn với thiết bị này nếu bạn không muốn mất đi các lượt viếng thăm.
5
6
Ngôn ngữ Javascript (hiện nay thông dụng hơn với tên gọi ECMAScript)
Ngôn ngữ này giúp cho người dùng tương tác với website thuận tiện hơn
9
8
Ngôn ngữ PHP
Giúp các website có nội dung liên tục thay đổi theo dữ liệu nằm trong Cơ sở dữ liệu.
7
8
Framework Laravel
Với framework này, việc phát triển một ứng dụng bằng PHP trở lên thật đơn giản. Tham khảo Khóa học Laravel trong 7 ngày nếu bạn muốn làm chủ framework này.
7
7
Nói chung nếu bạn xác định trở thành một lập trình viên web thì tất cả những kiến thức ở trên là cần thiết, “không bổ dọc thì bổ ngang”.
So sánh Vue.js với jQuery
jQuery là một thư viện JavaScript có thể chạy trên nhiều trình duyệt được thiết kế để đơn giản hóa các kịch bản HTML phía máy khách, nó hoàn toàn miễn phí và là phần mềm mã nguồn mở. jQuery được giới thiệu lần đầu tiên vào năm 2006 bởi John Resig, hiện nay jQuery là thư viện JavaScript phổ biến nhất, nó có mặt ở hơn 60% trong 100 nghìn website có thứ hạng đầu tiên. Cú pháp jQuery được thiết kế để dễ dàng “duyệt” qua tài liệu, lựa chọn các thành phần DOM, tạo các hiệu ứng hoạt họa, quản lý sự kiện và phát triển các ứng dụng Ajax. Đa số các lập trình viên web đều biết đến jQuery, như vậy bạn có thể tưởng tượng ra độ phổ biến cũng như hữu ích của jQuery. Tuy nhiên, khi các ứng dụng web ngày càng phát triển với độ phức tạp cao ví dụ như ứng dụng mạng xã hội Facebook, ứng dụng Gmail… các ứng dụng dạng đơn trang SPA, việc sử dụng jQuery khiến mã nguồn không thể kiểm soát được. Vue.js là một sự lựa chọn tiếp theo mà sau loạt bài giới thiệu về Vue.js này, bạn sẽ phải thốt lên “Thật kỳ diệu, thật tuyệt vời”.
Chúng ta hãy thử viết ví dụ Hello world của Vue.js bằng jQuery xem thế nào và cùng phân tích nhé:
<!DOCTYPE html><html><head><title>Ví dụ đầu tiên Vue.js chuyển đổi sang jQuery- allaravel.com</title></head><body><h1>Xin chào, tôi là Vue.js</h1><input type="text"value="Xin chào, tôi là Vue.js"><script src="https://code.jquery.com/jquery-3.3.1.min.js"></script><script type="text/javascript">$(document).ready(function(){$("input").on("change blur keyup mouseup",function(){$("h1").text(($(this).val()));});});</script></body></html>
Khi bạn trải nghiệm sẽ thấy giống với ví dụ đầu tiên sử dụng Vue.js, tuy nhiên cảm nhận có độ lag chút xíu hơn so với Vue.js tuy nhiên không phải vấn đề lớn. Vậy tại sao phải thay thế jQuery bởi Vue.js.
Chúng ta cùng xem xét vấn đề sau nhé. Giả sử bạn muốn cập nhật giá trị của ô nhập liệu <input> đến 100 thẻ <h1> khi đó bạn cần phải gán giá trị của 100 thẻ <h1> đó trong sự kiện thay đổi nội dung của <input> nếu sử dụng jQuery, với Vue.js bạn chẳng cần làm gì cả, 100 chứ 1000 thẻ <h1> cũng vậy, thay đổi dữ liệu ở Model tự động nó gán sang View.
Trên đây mới chỉ là vấn đề về số lượng, hãy xem tiếp logic sau, giả sử có hàng trăm thẻ <input> cùng thay đổi giá trị message và hiển thị lên hàng trăm thẻ <h1>, với jQuery khi viết code thật sự các sự kiện sẽ chồng lấn nhau và rất có khả năng dẫn đến treo cứng, giống như vài năm trước Facebook cũng đã từng không kiểm soát nổi trạng thái chồng chéo giữa các thành phần và cuối cùng phải sử dụng đến mô hình MVVM để giải quyết vấn đề này.
So sánh Vue.js với các framework cùng dạng
Hiện nay có rất nhiều các framework Javascript mạnh mẽ, kể đến có React (hậu thuẫn bởi Facebook), Angular (hậu thuẫn bởi Google), Ember, Riot, Polymer… tuy nhiên Vue.js đang là sự lựa chọn lý tưởng cho các ứng dụng web ở mức to vừa. Có mấy lý do như sau:
Hiệu năng Vue.js là thực sự đáng nể so với các đối thủ khác.
Vue.js có dung lượng tải cực bé do đã tách một số phần ra khỏi core như Vuex, vue-router… nó giúp cải thiện tốc độ tải của toàn trang.
Một lý do mà nhiều người tìm đến với Vue.js là tính đơn giản, dễ học, dễ áp dụng đặc biệt cho những người chưa có nhiều kiến thức nền.
Vue.js luôn học hỏi và tích hợp những gì tốt nhất từ các framework khác, nó cũng giống như framework Laravel nổi tiếng, luôn thay đổi và luôn tốt hơn.
Vue.js cũng có những yếu điểm, thứ nhất đội ngũ phát triển có hạn nên không thể có những tính năng để phát triển các hệ thống cực lớn, đấy là mình nghe đồn vậy chứ thực tế chưa kinh qua dự án nào mà không dùng được Vue.js. Thứ hai, Vue.js do Evan You, một người Mỹ gốc Trung Quốc phát triển đầu tiên, có một số bạn không thích nhưng mình thấy Trung Quốc mấy năm gần đây phát triển CNTT cực mạnh và chúng ta nên học tập họ.
Kết luận
Có rất nhiều thông tin được đề cập nhưng trong phần này bạn chỉ cần quan tâm đến mô hình MVVM hay gán dữ liệu hai chiều được sử dụng trong Vue.js. Bạn cũng yên tâm đây Vue.js rất dễ tìm hiểu, mình sẽ cố gắng sắp xếp kiến thức logic nhất, bên cạnh đó trong các phần tiếp theo, với mỗi bài viết sẽ có một vài bài tập nhỏ cho các bạn để vận dụng kiến thức được nhớ lâu hơn.
Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Thông thường, sử dụng Nginx với Docker, chúng ta sẽ không cài đặt Nginx từ official image rồi cấu hình manually. Chúng ta sẽ sử dụng những Inginx Docker Image đã được cấu hình sẵn và việc chúng ta cần làm là start container từ những Nginx Docker Image đó và sử dụng mà thôi. Trong bài viết này, mình sẽ hướng dẫn các bạn cách xây dựng một custom Nginx Docker Image các bạn nhé!
Mình sẽ tạo mới một Dockerfile sử dụng Ignix official image để bắt đầu:
FROM nginx:latest
Cấu hình trang web mặc định của Nginx khi chúng ta cài đặt Nginx từ Docker chứa trong tập tin /etc/nginx/conf.d/default.conf của Docker container đó các bạn! Nội dung của tập tin này như sau:
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
Mình sẽ không sử dụng cấu hình mặc định này nên mình sẽ remove nó trong tập tin Dockerfile như sau:
Kiến trúc của Selenium WebDriver đơn giản hơn rất nhiều so với Selenium RC. Selenium WebDriver làm việc trực tiếp với trình duyệt ở mức độ hệ điều hành trong khi Selenium RC làm việc với trình duyệt thông qua một hệ thống Server ảo – Selenium Remote Control (RC) Server. Nó cứ như có một người trung gian để chuyển lệnh từ test case của mình lên trình duyệt vậy.
Tốc độ
Tất nhiên, khi làm việc trực tiếp giữa hai người (Selenium WebDriver – trình duyệt) thì nó phải nhanh hơn làm việc thông qua người trung gian (Selenium RC – Selenium RC Server – trình duyệt) rồi hen.
Tương tác như đời thật
Với Selenium WebDriver, chúng ta không thể tương tác với các đồi tượng UI ẩn (hidden)/vô hiệu (disable) trong mã nguồn web. Ngược lại, với Selenium RC, chúng ta có thể làm mọi đồi tượng UI có trong mã nguồn, bất kể đồi tượng UI đó nó như thế nào trên UI. Điều này thực sự không tốt cho việc kiểm thử phần mềm vì nó bỏ qua các lỗi UI có thể có. Hơn nữa, trong đời thực, chúng ta không thể tương tác với các đồi tượng UI ẩn/vô hiệu.
Giao diện lập trình ứng dụng API – Application Programming Interface
Các APIs mà Selenium WebDriver cung cấp trong thư viện đơn giản hơn so với Selenium RC. Ví dụ như, với Selenium WebDriver, chúng ta chỉ có click; còn với Selenium RC, chúng ta có click, mouseDown, or mouseDownAt. Quá phức tạp phải không? Hơn nữa, khi sử dụng Selenium RC, chúng ta xác định hành động trước rối mới đền đối tượng UI (làm gì trên đối tượng nào); ngược lại, với Selenium WebDriver, chúng ta xác định đối tượng UI trước rồi mới nói đến làm gì trên nó (với đối tượng này chúng ta sẽ làm gì).
Bên cạnh đó, Selenium WebDriver không phải không có điểm yếu. Thứ mà mình không thích nhất của Selenium WebDriver đó là mã nguồn của nó không chạy trên Selenium Grid được. Cho nên, khi muốn thực thi test case với Selenium WebDriver trên nhiều trình duyệt khác nhau, chúng ta phải cấu hình bằng tay. Buồn là vậy….
Captcha là gì? Bao giờ thì chúng ta mới thoát được Captcha?
Bài viết được sự cho phép của blogchiasekienthuc.com
Thuật ngữ Captcha được công khai vào năm 2000 bởi một nhóm các chuyên gia khoa học máy tính: Luis von Ahn, Manuel Blum, Nicholas J. Hopper, và John Langford. Từ đó cho đến nay thì CAPTCHA đã để lại cho người dùng Internet không ít niềm vui cũng như nỗi buồn.
Niềm vui là dành cho cho các chủ trang web (Webmaster), bởi nhờ CAPTCHA mà trang web của họ tránh được vô số các cuộc tấn công ác ý với mục đích phá hoại (các hình thức DDOS ví dụ như Brute-force Login attack, Web-scraping,…)
Còn nỗi buồn là dành cho người tấn công và cả những người dùng phổ thông như chúng ta nữa, tự dưng chúng ta phải nhập những ký tự khó đọc vào khung xác nhận rồi mới có thể đăng nhập được, thậm chí là khi tìm kiếm hoặc vừa truy cập vào một trang web đã phải nhập CAPTCHA rồi.
Gọi là “nhập” CAPTCHA cho gần gũi, vì CAPTCHA phiên bản đầu tiên gắn liền với tuổi thơ của rất nhiều người. Người dùng phải nhập vào những con số, con chữ bị làm móp méo, biến dạng và làm mờ…
Còn hiện tại thì đa phần CAPTCHA bắt người dùng chúng ta click chuột để tìm “trụ nước chữa cháy”, “xe bus”, “đèn giao thông”, “tàu thuyền”… mọi thứ đã nhẹ nhàng hơn trước.
Một số biến thể của CAPTCHA còn bắt người dùng “xếp hình” nữa (ví dụ như chọn những mảnh ghép còn thiếu và đặt vào để hoàn thiện bức hình).
Bây giờ chúng ta sẽ tìm hiểu chi tiết hơn về khái niệm của Captcha nhé !
#1. CAPTCHA là gì?
CAPTCHA là viết tắt của cụm từ Completely Automated Public Turing test to tell Computers and Humans Apart, đây là một phương pháp kiểm tra kiểu challenge-response dùng trong điện toán (computing) để xác định lượt truy cập có phải là con người thật hay không, hay là Roboot, người máy..
Thực ra thì phiên bản sơ khai nhất của CAPTCHA (tức là Version 1) đã hình thành từ năm 1997 với ý tưởng ban đầu là bắt người dùng nhập lại các chữ (đã bị làm mờ, che một phần, làm biến dạng…) trong hình mẫu, một việc tưởng chừng rất đơn giản nhưng lại rất hiệu quả để ngăn ngừa các phần mềm, bot vượt qua.
Ngay từ khi mới hình thành thì CAPTCHA đã phải nhận rất nhiều những chỉ trích, không chỉ với những người mắc bệnh về mắt, về khả năng nhận thức kém, mà còn đối với cả những người bình thường như chúng ta nữa, bởi CAPTCHA khiến người dùng rất bực mình và mất thời gian.
Từ đó cho đến nay, cũng trên dưới 30 năm rồi, CAPTCHA đã trải qua nhiều lần cải tiến để vừa mang đến sự tiện lợi hơn cho người dùng, cũng như là để các nhà phát triển tối ưu thuật toán, các công ty như Google còn dùng CAPTCHA để “nhờ” người dùng “dịch các từ trong hình ra chữ” (reCAPCHA).
Google là đơn vị tiên phong cải tiến CAPTCHA bằng phiên bản mới của công ty: reCAPTCHA, ban đầu với version 1 thì reCAPTCHA cũng bắt người dùng đoán đúng chữ trong hình, nhưng sang đến version 2 thì nếu có dấu hiệu bất thường mới hiện reCAPTCHA lên.
Còn version 3 mới nhất của reCAPTCHA thì đã hoàn toàn chạy ngầm trong trang web/ trình duyệt web, tức là nó sẽ tự động phân tích người dùng với thuật toán thông minh, nên đa phần người dùng bình thường sẽ ít bị nó làm phiền.
Tìm hiểu thêm về lịch sử của Captcha trên Wikipedia !
#2. Lý do nên cho CAPTCHA “nghỉ hưu”?
Đơn giản là do mọi người đều ghét nó, cá nhân mình khi duyệt web qua Wi-Fi bình thường thì không sao, còn khi nào dùng VPN/Proxy thì y như rằng CAPTCHA hiện ra liên tục. Rất là bực !
Hoặc là khi chúng ta làm việc gì liên quan đến tìm kiếm nhiều (tìm kiếm trên Google Search) đó các bạn, lúc đó reCAPTCHA sẽ hiện ra, và chúng ta lại phải hoàn tất thủ tục thì mới xem được rất quả.
Kinh nghiệm là bạn hãy đăng nhập vào tài khoản Google trước khi tìm kiếm, như vậy sẽ giảm thiểu tối đa số lần hiển thị reCAPTCHA.
Mình xin nêu ra 4 vấn đề khiến mình rất bực về CAPTCHA:
Mất thời gian: Trung bình chúng ta mất 32 giây để giải xong CAPTCHA, mà trên thế giới có khoảng 6 tỷ người dùng Internet, giả sử cứ 10 ngày 1 người gặp 1 CAPTCHA => có thể ước tính nhân loại tốn thời gian = 500 năm lãng phí mỗi ngày chỉ để giải CAPTCHA, để chứng minh chúng ta là con người thật chứ không phải là robot =]]
Trở ngại: Những người khuyết tật về mắt hoặc những người bị suy giảm nhận thức có thể không giải được CAPTCHA để truy cập vào các trang web. Người mù thì chắc chắn phải khóc ròng rồi, vì đa phần các chương trình trợ năng như trên Windows đều không giải CAPTCHA thay con người được.
Nhận thức: Chắc chắn có nhiều người không biết trụ nước cứu hỏa màu đỏ huyền thoại của nước Mỹ, kết hợp thêm CAPTCHA toàn tiếng Anh thì chắc 1/4 dân số địa cầu cũng phải bó tay, gây ức chế.
Một ví dụ vui đó là CAPTCHA tiếng Anh có thể bắt bạn tìm “cab” trong hình (taxi ở New York hay London thì gọi là cab, ở châu Á toàn gọi là taxi), chưa kể “cab” ở NewYork màu vàng, còn ở London thì màu đen !
Người dùng di động: Xu hướng truy cập Internet đổ dồn về các điện thoại thông minh, tất nhiên thì CAPTCHA cũng gây tốn Pin/Data, chưa kể là màn hình nhỏ còn gây trở ngại rất nhiều cho người dùng.
#3. Giải pháp của CloudFlare
Dành cho bạn nào chưa biết thì CloudFlare (CF) thường được biết đến với dịch vụ tăng tốc độ website, tối ưu trang web, giảm tải cho trang web, dịch vụ DNS, chống lại các cuộc DDOS…
Khi bạn sử dụng dịch vụ CF cho trang web của bạn thì hCAPTCHA sẽ tự động xuất hiện khi lưu lượng truy cập đến trang web bị nghi là bot hoặc do tool tấn công (cái này bạn không phải cấu hình gì cả, dịch vụ CloudFlare này rất hay, bạn nên tìm hiểu thêm nhé).
Theo hãng này đề xuất thì phương thức test CAPTCHA nên được thay bằng Cryptographic Attestation of Personhood (mình gọi tắt là CAP).
Thông tin thêm: Với Cryptographic Attestation of Personhood thì người dùng chỉ mất tất cả 5 giây và yêu cầu tối đa 3 lần nhấp để hoàn thành việc xác thực, thay vì phải mất đến 32 giây cần để giải quyết CAPTCHA.
CloudFare sẽ sử dụng các Khoá bảo mật phần cứng (Hardware Security key), ví dụ như YubiKey, HyperFIDO hay Thetis FIDO U2F chẳng hạn) để triển khai giải pháp của họ, hoặc lấy smartphone làm trung tâm.
Mình xin giới thiệu mô hình demo của hãng:
Khi người dùng truy cập vào trang web được bảo vệ bởi CAP, ví dụ: com
Trường hợp này là trang web đó được bảo vệ thông qua dịch vụ của CloudFlare thì CloudFlare sẽ yêu cầu bạn giải CAP.
Người dùng click vào “I am human (beta)”, thì thay vì phải nhập chữ, chọn hình như CAPTCHA thì trình duyệt web sẽ yêu cầu bạn xuất trình thiết bị bảo mật (Security key chẳng hạn).
Người dùng cắm Hardware Security key (khóa bảo mật này có hình dáng tương tự USB), hoặc quét NFC từ smartphone.
Sau đó thì thông tin mã hóa chứa dữ liệu xác nhận bạn là con người thật (cryptographic attestation) sẽ được gửi về CloudFlare, như vậy những lần khác khi truy cập vào trang web đó/ hoặc các trang có sử dụng dịch vụ của CloudFlare bạn sẽ không bị làm phiền bởi những thứ như CAPTCHA nữa!
Trong tương lai thì CloudFare sẽ có thêm các thiết bị hỗ trợ cho quá trình xác thực với trang web đa dạng hơn, mình nghĩ là phương án sử dụng smartphone là hay nhất, chứ USB key có vẻ hơi bất tiện (dễ làm rơi/ bị đánh cắp).
Các bạn có thể tìm hiểu thêm về kỹ thuật của phương thức xác thực người dùng mới này từ CloudFlare:
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 đã hướng dẫn các bạn cách cài đặt Nginx trên CentOS. Nếu sử dụng Docker thì việc cài đặt Nginx sẽ như thế nào? Trong bài viết này, mình sẽ hướng dẫn cho các bạn nhé!
Đầu tiên, các bạn cần đi đến trang Docker Hub official build của Nginx https://hub.docker.com/_/nginx, chọn latest version của Nginx, sau đó thì sử dụng Docker command để start một Nginx server lên, ví dụ như sau:
docker run -d -p 80:80 --name web nginx
Nginx mặc định chạy ở port 80 và mình đã mapping với port 80 của máy host (máy chạy Docker). Ở đây, mình cũng đã sử dụng latest tag của Nginx nên mình không cần khai báo version, các bạn có thể chọn version mà mình muốn nhé!
Kết quả:
Lúc này, nếu các bạn đi đến http://localhost/, các bạn sẽ thấy kết quả như sau: